Specialised · Senior

OAuth, SSO & MFA Testing

Modern NZ applications don’t build their own login — they delegate to identity providers via OAuth 2.0, SAML, or OpenID Connect. Testing authentication is no longer about checking a username/password form. It’s about testing token flows, session federation, and MFA fallback paths that most testers never touch.

Senior Test Lead ISTQB CTAL-TA ~35 min read · ~75 min with exercises

1 The Hook

A Wellington government agency deploys RealMe login for a citizen-facing portal. The QA team tests the happy path: click “Login with RealMe”, authenticate, land on the dashboard. Sign-off complete. Six weeks after go-live, a penetration tester discovers that the OAuth state parameter is not validated — a classic CSRF attack vector in OAuth flows. An attacker can craft a malicious link that binds their OAuth token to a victim’s session. The agency’s QA team had tested that login worked, but never tested the security properties of the OAuth flow itself.

This is not an unusual story. Most QA teams test the outcome of authentication — “does the user land on the right page?” — and skip the protocol. But the protocol is where the vulnerabilities live. The state parameter exists specifically to prevent CSRF attacks. It’s mandatory in the OAuth 2.0 specification. Validating it is a single-line check. Nobody tested it.

The penetration tester found it in two hours. A tester who knew OAuth 2.0 would have found it in the same time, and found it before go-live.

2 The Rule

Testing authentication means testing the protocol, not just the outcome. A login that appears to work can still have a broken OAuth flow, an invalid token, or an MFA bypass. Test the state parameter, the token claims, the expiry, and the MFA negative paths — not just the happy path.

3 The Analogy

Analogy

A bank vault door that appears closed.

Testing OAuth by only checking that you land on the dashboard is like testing a bank vault by checking that the door is closed. You need to verify the combination lock works correctly, that the hinges can’t be removed from outside, and that the emergency override requires two keys. The door being closed doesn’t tell you any of that.

A QA team that tested “login works” confirmed the door was closed. The penetration tester checked the hinges. Both inspected the same vault. Only one of them checked the right things.

4 Watch Me Do It

Three key test scenarios for OAuth/SSO/MFA. Each one targets a class of vulnerability that a happy-path test misses entirely.

Test 1: OAuth state parameter validation (CSRF protection)

Scenario: Verify CSRF protection in OAuth flow Steps: 1. Start OAuth flow in Browser A → capture the state parameter from the redirect URL 2. Complete the OAuth flow in Browser B (different session) 3. Attempt to replay the OAuth callback URL from step 1 in Browser A Expected: Server rejects the reused/mismatched state with 400 or 401 Error message: "invalid_state" or equivalent Fail: Server accepts any state value — this is a CSRF vulnerability. An attacker can bind their own OAuth token to a victim's session.

Test 2: Access token expiry and refresh token rotation

Scenario: Access token expires; refresh token issues a new one Steps: 1. Log in → capture access_token and refresh_token from the token response 2. Wait for access_token to expire (or set expiry to 1 minute in test config) 3. Make an API call with the expired access_token Expected: 401 Unauthorized — "Token expired" 4. POST the refresh_token to the /token endpoint Expected: New access_token issued; refresh_token rotated (old one invalidated) 5. Make the same API call with the new access_token Expected: 200 OK 6. Attempt to reuse the old refresh_token Expected: 401 — "Token already used" (rotation enforced) Fail: Expired access tokens accepted; refresh tokens reusable after rotation.

Test 3: MFA bypass via direct URL navigation

Scenario: Authenticated session requires MFA — cannot be skipped Steps: 1. Enter valid username and password 2. When MFA prompt appears, directly navigate to /dashboard in the same browser tab Expected: Redirect back to MFA prompt — session not established without MFA 3. Intercept the MFA verification POST request Modify the OTP field to an incorrect value Expected: 401 — "Invalid code" — request rejected 4. Submit 5 consecutive incorrect OTP attempts Expected: Account temporarily locked or rate-limited after 3–5 failures 5. Test SMS backup code: submit an exhausted backup code Expected: Rejected — cannot re-use backup codes

After each OAuth flow, use Postman or jwt.io to decode the JWT access token (base64-decode the payload) and verify these claims:

{ "iss": "https://login.microsoftonline.com/{tenant-id}", // must match expected issuer "sub": "user-id-123", // subject — unique user identifier "aud": "api://your-app-client-id", // must match YOUR app, not anyone's "exp": 1749123456, // must be in the future "scope": "read:accounts", // must match what was requested — no elevation "amr": ["mfa"] // authentication method — confirms MFA was used }
Pro tip: The aud claim is the most commonly misconfigured. It should match your application’s client ID exactly. If it accepts any audience value, a JWT issued for a different app can be used against yours. Test this by using a token issued for a test app against your production API.

5 When to Use It

Apply this testing approach on any application that delegates authentication to an external identity provider. In the NZ context, that includes:

  • Government portals: RealMe (SAML 2.0), RealMe Verified (higher assurance)
  • Enterprise applications: Azure AD, Okta, Ping Identity
  • Consumer applications: Auth0, Google SSO, Apple Sign-In
  • Financial services: Any OAuth 2.0 consent flow (Open Banking, KiwiSaver platforms)

The minimum test coverage for any OAuth/SSO integration: state parameter validation, token expiry and refresh rotation, MFA bypass attempts, scope enforcement (a token with read scope cannot access write endpoints), logout that invalidates the session server-side, and re-authentication when a privileged action is requested.

6 Common Mistakes

🚫 “I used to think: if the login page works, SSO is tested.”

Actually: SSO has at least six testable flows — initial login, token refresh, single-logout (one app), global logout (all apps in the federation), session timeout, re-authentication for privileged actions, and MFA step-up. Testing one flow tells you nothing about the others. A pen tester finding a session that persists after logout is a common NZ government finding.

🚫 “I used to think: MFA testing just means checking you can enter an OTP.”

Actually: The critical MFA tests are the negative ones. Can you skip MFA by navigating directly to the post-login URL? Is the OTP rate-limited after 3 failed attempts? What happens when backup codes are exhausted? Is MFA required again after a session timeout, or does the app trust a stale session cookie? These are the gaps that get exploited.

🚫 “I used to think: JWT tokens are validated by the app automatically, so I don’t need to test them.”

Actually: Decode the JWT and verify the claims yourself. Check exp is set and in the future, aud matches your app, scope matches what was requested, and iss matches the expected identity provider. Misconfigured token validation is a recurring vulnerability in NZ security audits — libraries often have insecure defaults that accept any issuer or any audience.

7 Now You Try

📋 Prompt Lab — Write OAuth/SSO Test Cases

A NZ KiwiSaver portal uses Azure AD SSO for employer logins. Write 6 test cases covering: (1) the happy path login, (2) token expiry and renewal, (3) MFA bypass attempt via direct URL, (4) invalid state parameter, (5) logout that invalidates the session, and (6) scope enforcement — an employer cannot access member-only API endpoints.

8 Self-Check

Click each question to reveal the answer.

Q1: What is the OAuth state parameter and why must it be validated?

The state parameter is a random, opaque value generated by the client at the start of an OAuth flow and returned unchanged by the authorisation server in the callback. Validating it proves the callback corresponds to the flow the client started — not a forged request from an attacker. Without validation, an attacker can craft a malicious link that binds their OAuth token to a victim’s session (session fixation via CSRF).

Q2: A user logs out of your application. What additional step is needed to properly invalidate an SSO session?

The application must call the identity provider’s logout endpoint (single logout / SLO) to invalidate the session at the IdP level, not just clear the local session cookie. Without this, a user who logs out of your app can immediately log back in without re-authenticating, because their IdP session is still active. In federated SSO, the IdP may also need to notify other relying parties of the logout (global logout).

Q3: What claims should you verify in a JWT access token during security testing?

iss (issuer) — must match the expected identity provider URL. aud (audience) — must match your application’s client ID exactly, not just any value. exp (expiry) — must be in the future and set to a reasonable duration. scope — must match what was actually requested; no elevation to higher scopes. amr (authentication method reference) — confirms MFA was completed when required. A misconfigured aud is the most common finding: tokens issued for another app should be rejected by yours.

9 ISTQB Mapping

CTAL-TA v3.1.2 — Section 3.2.5: Security testing of web services and authentication flows

The CTAL-TA syllabus covers security testing of web services, including authentication and authorisation flows. OAuth 2.0 state validation, token claim verification, and MFA bypass testing are direct applications of Section 3.2.5. Also relevant: CTFL v4.0 Section 4.1.1 (non-functional characteristics — security), which positions security as a quality characteristic that testers must actively verify, not assume. The OWASP Testing Guide (v4.2) Section 4.5 covers OAuth and authentication testing in full and is the primary technical reference for this lesson.