The OAuth vulnerability catalog
What it is
A structured list of the ways OAuth and OIDC deployments are broken, organised by where in the flow the flaw lives. It complements the OAuth grants and tokens page: that page is how to do it correctly, this is what goes wrong and why each mitigation exists.
The flaws cluster into five places:
1. The redirect_uri the most exploited surface
2. The authorization request (state, PKCE, response_type)
3. The token itself (validation, confusion, leakage)
4. The token lifecycle (refresh, revocation, storage)
5. The trust relationships (mix-up, IdP confusion, open redirects)
What this is confused with: application bugs. These are protocol-level flaws that appear across implementations, which is why they have names and RFCs. A team that has never read the OAuth Security BCP is running some subset of these, because the defaults and the tutorials predate the attacks.
The catalog
1. redirect_uri attacks: the largest surface
The redirect_uri is where the authorization code or token is delivered, so controlling it means stealing the grant.
Open redirect chaining:
Registered: https://app.example/callback
Attacker: https://app.example/callback?next=https://attacker.example
-> if the app redirects to `next` after the callback,
the code travels to the attacker.
Loose matching:
Registered: https://app.example/callback
Accepted (misconfigured):
https://app.example.attacker.com/callback (suffix match)
https://app.example/callback/../evil (path traversal)
https://app.example@attacker.com/callback (userinfo confusion)
The defence is exact string matching, mandated by OAuth 2.1. Not prefix, not domain, not regex: the redirect_uri presented must equal a registered one byte for byte. Every loose matcher is a code-theft vector, and the reason exact matching is in the spec is that every looser scheme was exploited.
2. Authorization request attacks
Missing state (CSRF):
An attacker starts an OAuth flow, gets an authorization code for THEIR
account, and tricks the victim into completing it, linking the attacker's
identity to the victim's session.
state binds the flow to the user's session and must be verified on the callback. It is
distinct from PKCE (which protects the code, not the session) and both are required.
Missing PKCE (code interception): covered on the OAuth page; on mobile, a malicious app registering the same custom scheme intercepts the code.
response_type downgrade: an attacker manipulates the flow to use the implicit grant
(response_type=token) where the token appears in the URL, if the server still supports it.
OAuth 2.1 removing implicit closes this, and until then the server must reject implicit
explicitly.
3. Token attacks
Algorithm confusion (alg: none, RS256->HS256): the highest-impact JWT flaw, covered in
detail on the OAuth page. Pin the algorithm; never read it from the token.
Missing audience validation: a token minted for one service accepted at another, because they share a signing key. The most common validation gap (see the OAuth page's 2-of-12 finding).
Token leakage via Referer:
A token in a URL (implicit grant, or a token in a query parameter) leaks
in the Referer header when the page loads a third-party resource, and in
browser history, and in server logs.
Tokens belong in headers or POST bodies, never in URLs, which is the other reason implicit is dead.
Insufficient token binding: a bearer token stolen by any means works from anywhere. DPoP and mTLS-bound tokens address this (OAuth page), and their absence is not a bug so much as a missing defence for high-value contexts.
4. Lifecycle attacks
Refresh token theft without rotation: a stolen refresh token works until expiry, silently. Rotation with reuse detection makes theft detectable and bounded (OAuth page).
Token stored insecurely:
SPA storing tokens in localStorage: readable by any XSS.
SPA storing tokens in a cookie without HttpOnly: readable by XSS.
Native app storing tokens in plaintext: readable by any app with
filesystem access.
The BCP recommendation for SPAs is the BFF (backend-for-frontend) pattern: the token lives in the backend, and the browser holds only a session cookie (HttpOnly, Secure, SameSite), so an XSS cannot exfiltrate a usable token. In-browser token storage is a compromise, and the BFF is the way to avoid it.
Insufficient revocation: a JWT is valid until it expires regardless of logout, so a "logout" that only clears the client leaves a working token (see JWT revocation).
5. Trust-relationship attacks
The IdP mix-up attack: the subtle one, and worth understanding because it is not obvious.
The client supports two IdPs: an honest one and an attacker's.
1. The victim starts a flow choosing the attacker's IdP.
2. The attacker relays the request to the HONEST IdP.
3. The victim authenticates at the honest IdP; the code comes back.
4. The client, thinking it is talking to the attacker's IdP, sends the
code (and the client secret) to the ATTACKER'S token endpoint.
5. The attacker now has a code for the victim's honest-IdP account.
The defence is the iss parameter in the authorization response (RFC 9207): the response
carries which IdP issued it, so the client detects that the honest IdP's code arrived through
the attacker's flow. Without it, a client supporting multiple IdPs is vulnerable, and this
is why the iss response parameter was standardised.
Cross-site request forgery on the token endpoint and client impersonation round out the trust category, both addressed by client authentication and PKCE for the code exchange.
The prioritised checklist
In the order that catches the most, for the least effort:
1. Exact redirect_uri matching closes the largest surface
2. Audience validation on every API the most common real gap
3. Algorithm pinning (no alg from token) the highest-impact JWT flaw
4. state + PKCE on every flow CSRF + code interception
5. Tokens out of URLs and localStorage leakage; BFF for SPAs
6. Refresh rotation + reuse detection bounded, detectable theft
7. iss response parameter (multi-IdP) mix-up attack
8. Revocation strategy logout that means something
Items 1 through 3 catch the majority of real-world OAuth vulnerabilities, and they are the three most often missing, because the flow works without them.
A worked example: an OAuth audit finding four of the five categories
A B2B platform with SSO, supporting Google, Microsoft and a customer's own IdP. An audit against the catalog.
Findings, by category:
1. redirect_uri:
FINDING: prefix matching. https://app.example/callback matched
https://app.example/callback-attacker. A registered path prefix,
not an exact URI.
-> exact matching enforced. 3 legitimate redirect_uris were
enumerated and registered explicitly.
2. authorization request:
FINDING: state was generated but NOT VERIFIED on the callback for
one of the three login paths (a legacy path).
-> state verification made mandatory in shared middleware, so no
path can skip it.
3. token:
FINDING: no audience validation (the recurring one), AND the mobile
app stored the access token in plaintext SharedPreferences.
-> audience validation added; mobile token moved to the OS keystore
(Keychain/Keystore).
4. lifecycle:
FINDING: the SPA held tokens in localStorage; an XSS in a
third-party analytics script could have exfiltrated them.
-> moved to a BFF: the token lives server-side, the browser holds
an HttpOnly session cookie.
5. trust:
FINDING: supporting three IdPs with NO iss response parameter
handling, so a mix-up attack was possible.
-> RFC 9207 iss validation added; the client verifies the code
came from the IdP it initiated with.
Four of the five categories had a live finding, which is typical: an OAuth deployment that predates the Security BCP accumulates them because each individual flaw is invisible while the happy path works.
The prioritisation, as the deliverable:
Finding Severity Effort Order
──────────────────────────────────────────────────────
Prefix redirect matching critical low 1
No state verification high low 1
No audience validation high low 1
Plaintext mobile token high medium 2
localStorage tokens (SPA) medium high 3 (BFF is a project)
No iss handling (mix-up) medium medium 2
The three critical-or-high-and-low-effort items shipped in a week; the BFF migration was a quarter. That ordering is the point of a catalog: it turns "our OAuth might be insecure" into a ranked list of specific, known flaws with known fixes.
The finding that surprised the team was the mix-up attack, because it required understanding
that supporting multiple IdPs introduces a class of vulnerability that a single-IdP deployment
does not have. The iss response parameter existed for exactly this and they had never
enabled it, which is the pattern across the catalog: the defence is standardised because the
attack is known, and it is off because the flow works without it.
Production evidence
The OAuth 2.0 Security Best Current Practice (RFC 9700) is the authoritative catalog and the source of the mitigations here. It exists because the original OAuth 2.0 RFCs left enough latitude that insecure deployments were common, and it consolidates a decade of attack research.
Exact redirect_uri matching is mandated by OAuth 2.1, and the redirect_uri surface has been the subject of the most OAuth security research, from Egor Homakov's early work through to ongoing bug-bounty findings.
The mix-up attack was formalised by Fett, Küsters and Schmitz (2016) and the iss response
parameter (RFC 9207) is the direct fix. That a formal analysis produced a new RFC is a good
illustration of how the catalog grows: attacks are found, analysed, and mitigated in the spec.
Algorithm confusion has affected many JWT libraries, catalogued by Auth0 and others, and the resulting library-API changes (requiring the algorithm as a parameter) are the ecosystem's response.
The BFF pattern for SPAs is the current BCP recommendation for browser-based apps, reflecting the conclusion that in-browser token storage cannot be made safe against XSS and the token should not be in the browser at all.
The debate
Which flaws matter most? redirect_uri, audience validation and algorithm pinning, because they are high-impact and the most commonly missing. The catalog is long and the top three catch the majority of real vulnerabilities, so a team with limited time should fix those first and treat the rest as a follow-on.
Is the mix-up attack worth worrying about? Only if you support multiple IdPs, and then yes,
because it is not obvious and the iss parameter fix is cheap. A single-IdP deployment does not
have this class, which is a reason to be cautious about adding IdP flexibility without adding the
mitigation.
Should SPAs hold tokens at all? The BCP says no: use a BFF, so the token is server-side and the browser holds a session cookie. The objection is that a BFF is a stateful backend the SPA was trying to avoid, and the answer is that in-browser tokens are exfiltrable by XSS and the BFF is the only way to make that class impossible rather than merely unlikely. DPoP with a non-extractable key is the middle ground where a BFF is genuinely impractical.
How do you keep the catalog current? Read the BCP updates, because the catalog grows as
attacks are found and RFCs standardise mitigations. A deployment is secure against the attacks
known when it was built, and the iss parameter is an example of a mitigation that did not
exist when many deployments were written. Periodic re-audit against the current BCP is the
practice.
Follow-up Q&A
"What is the most exploited part of OAuth?"
The redirect_uri, because it is where the authorization code or token is delivered, so controlling it steals the grant. The attacks are open-redirect chaining and loose matching (suffix, path traversal, userinfo confusion), and the defence is exact string matching, mandated by OAuth 2.1. Every looser matching scheme has been exploited, which is why the spec requires byte-for-byte equality.
"What is the mix-up attack?"
A client supporting multiple IdPs can be tricked into sending a code obtained from an honest IdP
to an attacker's token endpoint. The victim starts a flow choosing the attacker's IdP, the
attacker relays it to the honest IdP, the victim authenticates, and the client sends the
resulting code to the attacker because it thinks it is talking to the attacker's IdP. The fix is
the iss response parameter (RFC 9207): the authorization response says which IdP issued it, so
the client detects the mismatch. It only affects multi-IdP deployments.
"Where should an SPA store its tokens?"
Ideally not in the browser at all: the BCP recommends a backend-for-frontend, where the token lives server-side and the browser holds an HttpOnly, Secure, SameSite session cookie, so an XSS cannot exfiltrate a usable token. localStorage and non-HttpOnly cookies are both readable by XSS. Where a BFF is impractical, DPoP with a non-extractable WebCrypto key limits a stolen token to the session rather than making it exfiltrable.
"What are the top three things to fix in an OAuth deployment?"
Exact redirect_uri matching (the largest attack surface), audience validation on every API (the
most common real gap, because the token validates without it), and algorithm pinning so the
verifier never takes the algorithm from the token (the highest-impact JWT flaw, enabling
alg: none and RS256-to-HS256 confusion). Those three catch the majority of real-world OAuth
vulnerabilities and are the three most often missing, because the flow works without them.
"How does a deployment accumulate these?"
Each individual flaw is invisible while the happy path works, so nothing fails during development to prompt the fix. An OAuth deployment predating the Security BCP accumulates a subset because the defaults and the tutorials predate the attacks, and the mitigations are off because the flow works without them. In one audit, four of the five flaw categories had a live finding, which is typical.
Common misconceptions
"OAuth is secure by default." The original RFCs left enough latitude that insecure deployments are common, which is why the Security BCP exists. Exact redirect matching, audience validation and algorithm pinning are all things you must do, not defaults.
"These are application bugs." They are protocol-level flaws that recur across implementations, which is why they have names and RFCs. A deployment that has never been audited against the BCP is running some subset.
"State and PKCE are redundant." State protects the session against CSRF; PKCE protects the code against interception. Different attacks, both required.
"The mix-up attack is theoretical." It was formally analysed and produced a new RFC. It
affects any multi-IdP client without iss validation, which is a large fraction of them.
"Tokens in localStorage are fine with a good CSP." A CSP reduces XSS risk and does not eliminate it, and a single XSS exfiltrates every token in localStorage. The BFF makes the token unreachable rather than merely harder to reach.
Interview delivery note
Say this verbatim: "The three that catch the most are exact redirect_uri matching, audience
validation, and algorithm pinning, and they are the three most often missing because the flow
works without them. The subtle one worth knowing is the mix-up attack: a client supporting
multiple IdPs can be tricked into sending an honest IdP's code to the attacker's token endpoint,
and the fix is the iss response parameter, which most multi-IdP deployments never enabled."
The high-value three plus the non-obvious one that signals depth.
The senior-versus-staff separator is the mix-up attack. A senior engineer knows redirect_uri
matching, state, PKCE and audience validation. A staff engineer knows that supporting multiple
IdPs introduces a distinct vulnerability class that a single-IdP deployment does not have, can
explain the relay mechanism, and knows that RFC 9207's iss parameter is the standardised fix
that is off by default. Understanding that the defence exists because the attack was formally
proven is the depth signal.
The second signal is the BFF recommendation for SPAs, with the reasoning: in-browser tokens are exfiltrable by any XSS, and the BFF makes the token unreachable rather than harder to reach, which is the difference between mitigation and elimination.
Further reading
- RFC 9700, the OAuth 2.0 Security Best Current Practice, which is the authoritative catalog.
- RFC 9207 (the
issauthorization response parameter) and Fett, Küsters and Schmitz's mix-up attack analysis. - The OAuth 2.1 draft, for the mandated exact redirect matching and the removed grants.
- The OWASP guidance on the BFF pattern for SPA token storage.