Key Takeaways

  • OAuth 2.0 is an authorization framework, not authentication (use OpenID Connect for identity).
  • PKCE (Proof Key for Code Exchange) is mandatory for public clients and SPAs.
  • Never store tokens in localStorage—use httpOnly cookies or in-memory storage.
  • Always validate redirect_uri strictly to prevent authorization code theft.

OAuth 2.0 powers "Login with Google/Facebook" across millions of applications. But a single misconfiguration can expose user accounts to complete takeover. This guide covers every attack vector.

How OAuth 2.0 Works

OAuth 2.0 defines four main roles: Resource Owner (user), Client (your app), Authorization Server (Google, etc.), and Resource Server (API). The most common flow is the Authorization Code Grant:

  1. User clicks "Login with Google"
  2. Browser redirects to Google's authorization endpoint
  3. User authenticates and consents
  4. Google redirects back with an authorization code
  5. Your server exchanges the code for an access token
  6. Use the token to access user data

Critical Vulnerabilities

1. Authorization Code Interception

If the redirect_uri isn't strictly validated, attackers can steal authorization codes:

// Vulnerable: Open redirect allows code theft
https://auth.example.com/authorize?
  client_id=app123&
  redirect_uri=https://evil.com/callback&  // Attacker's domain!
  response_type=code&
  scope=read:profile
Attack Scenario:

Attacker crafts a malicious link. When victim clicks it, the authorization code is sent to the attacker's server. The attacker exchanges it for an access token → full account access.

2. PKCE Bypass

PKCE (Proof Key for Code Exchange) prevents code interception by requiring a secret verifier. But some implementations allow downgrade attacks:

// Server should REJECT if code_challenge was sent but code_verifier is missing
POST /token
  code=abc123&
  redirect_uri=https://app.com/callback
  // Missing code_verifier! Server should error.

3. Implicit Flow Token Theft

The implicit flow returns tokens directly in the URL fragment, making them vulnerable to:

Fix: Use Authorization Code + PKCE

The implicit flow is deprecated. Always use the Authorization Code flow with PKCE, even for SPAs. Tokens should never appear in URLs.

4. State Parameter Missing

Without the state parameter, attackers can perform CSRF attacks to link their account to another user's session:

// Always include state and validate it!
const state = crypto.randomUUID();
sessionStorage.setItem('oauth_state', state);

const authUrl = `https://auth.example.com/authorize?
  client_id=app123&
  redirect_uri=https://app.com/callback&
  state=${state}&  // Random, unpredictable value
  response_type=code`;

5. Token Storage Vulnerabilities

Storage MethodXSS RiskCSRF RiskRecommendation
localStorageHighNone❌ Avoid
sessionStorageHighNone⚠️ Better
HttpOnly CookieNoneMedium✅ Best
In-Memory (Variable)MediumNone✅ Good for SPAs

Secure Implementation Checklist

Do
  • Use PKCE for all clients
  • Validate redirect_uri exactly
  • Implement state parameter
  • Use short-lived access tokens
  • Rotate refresh tokens
Don't
  • Use implicit flow
  • Store tokens in localStorage
  • Accept partial redirect_uri matches
  • Skip token validation
  • Expose client_secret in frontend

Frequently Asked Questions

What's the difference between OAuth and OpenID Connect?
OAuth 2.0 is for authorization (granting access to resources). OpenID Connect (OIDC) is built on top of OAuth and adds authentication (verifying user identity). Use OIDC when you need to know who the user is.
Is it safe to use "Login with Google" for sensitive apps?
Yes, if implemented correctly. Google's OAuth implementation is secure, but your app must properly validate tokens, use PKCE, and securely store credentials. For highly sensitive apps, consider additional factors like MFA.
How do I test OAuth security?
Use tools like Burp Suite to intercept OAuth flows. Test: redirect_uri bypass, missing state validation, PKCE downgrade, token exposure in logs, and scope escalation. OWASP has detailed OAuth testing guides.

Secure your authentication layer.
Read JWT Security Guide