OAuth Hacking: The Complete Guide to OAuth and OIDC Attacks

OpenID Connect Security

OIDC for testers: the ID token as a signed JWT, the sub/iss/aud/nonce claims, discovery and JWKS, and where OIDC trust assumptions break into identity forgery.

Published

OpenID Connect is the identity layer on OAuth, and its core artifact is the ID token: a signed JWT that asserts who the user is. The attacks are a mix of JWT signature tricks and OIDC-specific claim-validation gaps. This page covers both. Practice on a free live target.

OAuth is authorization, OIDC is authentication

Plain OAuth gives the client an access token to call APIs on your behalf. It never actually tells the client who you are. OIDC adds that: alongside the access token, the provider returns an ID token describing the authenticated user. That is the difference between "this app may read your calendar" and "this app knows you are [email protected]."

The ID token

The ID token is a JWT with identity claims. Decoded, its payload looks like this:

{
  "iss": "https://auth.example.com",
  "sub": "248289761001",
  "aud": "app123",
  "exp": 1811800000,
  "iat": 1811796400,
  "nonce": "n-0S6_WzA2Mj",
  "email": "[email protected]"
}

Each claim carries a guarantee the client must actually check:

  • iss is the issuer. It must equal the expected provider's URL.
  • sub is the stable user identifier. The client should key the account on iss plus sub, not on email.
  • aud is the audience. It must be this client's ID, or a token minted for another app is accepted here.
  • nonce ties the token to this login, defeating replay.
  • exp is expiry, and iat (issued-at) is also required, so check the token is fresh and unexpired.

Discovery and JWKS

Providers publish their configuration at a well-known path, which tells you the endpoints and the signing keys:

GET /.well-known/openid-configuration HTTP/1.1
Host: auth.example.com
{
  "issuer": "https://auth.example.com",
  "authorization_endpoint": "https://auth.example.com/authorize",
  "token_endpoint": "https://auth.example.com/token",
  "jwks_uri": "https://auth.example.com/.well-known/jwks.json"
}

The jwks_uri holds the public keys that verify ID-token signatures. This document is your map of the provider.

Where the trust assumptions break

OIDC fails when the client skips a check:

no signature check        a forged or alg:none token is accepted   (see JWT)
jku / x5u injection       header points at attacker-hosted keys     (see JWT)
issuer confusion          a token from provider A accepted where B was expected
audience not checked      a token minted for another client is accepted
sub vs email keying       linking on the email claim instead of iss+sub
nonce not checked         an old ID token is replayed

The signature-level attacks (alg:none, jku/x5u) are the same ones in JWT. The claim-level ones (iss, aud, nonce, sub) are OIDC-specific. Test both.

Edge variants

request_uri=https://attacker.tld/req   the AS fetches your request object -> SSRF (see /learn/ssrf)
id_token replay                        reuse a captured ID token where nonce is unchecked
mix-up attack                          confuse a client talking to multiple providers about which issued the code

Fixing it

  • Validate the signature, iss, aud, exp, and nonce on every ID token, and pin the JWKS.
  • Key accounts on iss plus sub, never on a mutable email claim.
  • Reject alg:none and attacker-supplied key URLs (jku/x5u).

Full guidance is in preventing OAuth attacks. Next, attack the most common OAuth flaw in redirect_uri manipulation, or try OIDC on a free lab.

← Back to OAuth Hacking: The Complete Guide to OAuth and OIDC Attacks