← Blog/Authentication

OAuth 2.0 Security Vulnerabilities Every Developer Should Know (And How to Fix Them)

OAuth 2.0 is the backbone of modern API authorization — and one of the most frequently misimplemented security protocols in production. These vulnerabilities are subtle enough to pass code review and dangerous enough to cause account takeover.

·9 min read

OAuth 2.0 is not a simple protocol. It's a framework — deliberately flexible, with multiple grant types, optional security parameters, and significant implementation responsibility left to developers. That flexibility is also why OAuth implementations are a reliable source of high-severity vulnerabilities.

These aren't theoretical attack classes from academic papers. They're vulnerabilities found regularly in production APIs, OAuth libraries, and even well-known identity providers. If you've implemented OAuth — either as a client or as an authorization server — this applies to you.

Vulnerability 1: Missing State Parameter (CSRF on OAuth Flow)

The state parameter in OAuth 2.0 exists specifically to prevent CSRF attacks against the authorization callback. Without it, an attacker can trick a victim's browser into completing an authorization flow that the attacker initiated — linking the victim's account to the attacker's identity provider account, or completing other account-linking flows.

The attack works because OAuth callbacks are predictable HTTP endpoints. If your callback handler doesn't validate a state parameter that was bound to the user's session at authorization initiation, anyone can craft a valid callback URL.

Fix: Generate a cryptographically random state value before redirecting to the authorization server. Store it in the user's session. On callback, verify that the state parameter matches what you stored. Reject any callback that doesn't match.

Vulnerability 2: Open Redirect in redirect_uri

The redirect_uri parameter tells the authorization server where to send the authorization code after the user approves. If the authorization server doesn't strictly validate this URI against a pre-registered allowlist, an attacker can manipulate it to redirect the authorization code to an attacker-controlled server.

Common validation failures: prefix matching instead of exact match (allows https://yourapp.com.evil.com/callback), path traversal tolerance (allows https://yourapp.com/callback/../../../attacker), or accepting any subdomain (allows https://attacker.yourapp.com/callback).

Fix: If you're building an authorization server: require exact match redirect URI validation against a pre-registered list. No wildcards. No prefix matching. If you're a client: register the most specific redirect URI possible and validate that the authorization code you receive was intended for your application.

Vulnerability 3: Authorization Code Interception (Missing PKCE)

PKCE (Proof Key for Code Exchange, pronounced "pixy") was designed to prevent authorization code interception attacks in public clients — native apps and SPAs where you can't safely store a client secret. Without PKCE, if an attacker can intercept an authorization code (through a malicious app on the same device, a redirect URI misconfiguration, or referrer header leakage), they can exchange it for tokens.

The OAuth 2.1 draft mandates PKCE for all authorization code flows. Many OAuth providers already require it. But plenty of legacy integrations still omit it.

Fix: Always use PKCE for authorization code flows, even for confidential clients. Generate a random code_verifier, hash it to create a code_challenge, include the challenge in the authorization request, and send the verifier with the token exchange request.

Check your API's authentication configuration

Scantient scans OAuth endpoints and authentication flows from the outside. Free scan, 60 seconds.

Scan Your API Free →

Vulnerability 4: Token Leakage via Referrer Header

If access tokens or authorization codes are passed as URL query parameters and the application subsequently navigates to a third-party resource (analytics script, embedded content, external link), the token appears in the Referer header of the outgoing request. The third-party server now has your user's token.

This is why the implicit grant type (which returned tokens in the URL fragment) was deprecated. But authorization codes in query parameters have the same problem when logging or referrer leakage is present.

Fix: After processing an authorization code from the URL, immediately redirect to a clean URL (remove the code and state parameters). Use Referrer-Policy: no-referrer or origin-when-cross-origin as a defense-in-depth header. Never pass access tokens as URL parameters.

Vulnerability 5: Insufficient Scope Validation

OAuth scopes define what an access token is authorized to do. If your API doesn't validate that the token's scopes match what the requested endpoint requires, a token issued for read-only access might grant write access, or a token issued for one resource might grant access to all resources.

This is the OAuth equivalent of broken object-level authorization — it's one of the most common API security mistakes in production systems that use OAuth.

Fix: Enforce scope checks in every route handler, not just at the authentication middleware level. Use a clear scope naming convention. When issuing tokens, apply least-privilege — only include scopes the application actually needs.

Vulnerability 6: Implicit Grant Type Usage

The implicit grant type was designed for SPAs when cross-origin requests were a limitation. It returns access tokens directly in the URL fragment — no code exchange, no client secret. It was deprecated in OAuth 2.0 Security Best Current Practice (RFC 9700) and should not be used in new implementations.

Tokens in URL fragments are accessible to any JavaScript on the page, appear in browser history, and are vulnerable to fragment identifier leakage. The authorization code flow with PKCE achieves the same goal for SPAs without these risks.

Fix: Migrate any implicit grant integrations to authorization code flow with PKCE. If you're an authorization server, disable the implicit grant type.

Vulnerability 7: Client Credential Exposure

OAuth client secrets in public clients (SPAs, mobile apps) are not secret — they're embedded in code that users can inspect. Using client secrets in these contexts provides no security benefit and creates a false sense of security.

This also appears as client secrets committed to version control, included in CI environment variables with overly broad access, or passed in URL parameters instead of the Authorization header. The full API security guide covers credential management in detail.

Fix: Don't use client secrets in public clients — use PKCE instead. For confidential clients, pass client credentials via the Authorization header (HTTP Basic auth), not as query parameters. Store client secrets with the same rigor as any other credential.

Vulnerability 8: Missing Token Binding / Audience Validation

Access tokens are often treated as bearer tokens — whoever has the token can use it. If a token issued for one API is accepted by another API without audience validation, a compromised token for a low-privilege service can be replayed against a high-privilege one.

JWT access tokens should include an aud (audience) claim specifying the intended recipient API. Each API should verify that the token's audience matches its own identifier. Without this, tokens can be reused across services.

Fix: Include an aud claim in all JWT access tokens. Validate the audience claim in every API that accepts tokens. For JWT security best practices more broadly, see our dedicated guide.

OAuth Security Checklist

  • state parameter generated and validated on every authorization flow
  • redirect_uri validated with exact match against registered allowlist
  • ✅ PKCE used for all authorization code flows
  • ✅ Tokens not passed as URL parameters; referrer policy set
  • ✅ Scope validation enforced per-endpoint, not just at middleware
  • ✅ Implicit grant type disabled
  • ✅ Client secrets not present in public clients
  • ✅ JWT access tokens include aud claim; audience validated by all APIs

Scan Your API Free — 60 Seconds

External security scan catches authentication issues, misconfigured headers, and exposed endpoints. No signup. No SDK.