← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

OAuth 2.0

Security CWE-287 OWASP A7:2021 Intermediate
debt(d7/e7/b7/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate semgrep can catch specific patterns like missing state parameter validation, but automated detection is explicitly marked 'no'. Most OAuth misimplementations (wrong flow choice, insecure token storage, lax redirect_uri matching) require manual code review or security testing to surface — they won't be caught by default tooling and often only manifest under adversarial conditions.

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix sounds simple in principle, but remediating a misimplemented OAuth flow (e.g. switching from Implicit to Authorization Code + PKCE, fixing token storage from localStorage to HttpOnly cookies, adding state validation everywhere) typically requires touching the auth initialization, all callback handlers, client-side token storage, and potentially backend session management — spanning multiple files and architectural layers.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). OAuth 2.0 is a foundational auth choice that shapes how every API call, session, and third-party integration is structured. Token lifecycle management, refresh logic, and storage strategy permeate frontend and backend code. Every feature that touches protected resources is shaped by how OAuth was implemented, making it a high-reach, load-bearing choice across the system.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The canonical misconception is explicit and significant: developers routinely treat OAuth 2.0 as an authentication protocol when it is strictly an authorisation framework — a mistake that leads to identity spoofing vulnerabilities. Additionally, the common mistakes list reveals multiple serious gotchas (Implicit flow deprecation, state parameter CSRF, localStorage token storage, redirect_uri matching) that contradict intuitive expectations and differ from how similar-looking patterns work in other auth systems.

About DEBT scoring →

Also Known As

OAuth OAuth2 Authorization Code flow PKCE access token refresh token

TL;DR

An authorisation framework that lets users grant third-party applications limited access to their resources without sharing passwords — using short-lived access tokens issued via defined flows for different client types.

Explanation

OAuth 2.0 (RFC 6749) separates authentication from authorisation: the resource owner (user) grants a client (app) access to resources on a resource server via an authorisation server that issues tokens. The main grant types: Authorization Code (web apps — exchanges a code for tokens via back channel), Authorization Code + PKCE (public clients — mobile/SPA where client secret cannot be kept), Client Credentials (machine-to-machine — no user involved), and Device Code (TV/CLI — polls for user approval on a separate device). Access tokens are short-lived (minutes to hours); refresh tokens allow getting new access tokens without re-prompting the user. Scopes define the permissions granted. Common security issues: missing PKCE on public clients enables code interception attacks; missing state parameter enables CSRF on the redirect; open redirect in redirect_uri enables token theft; storing access tokens in localStorage exposes them to XSS. In PHP, use a battle-tested library (league/oauth2-client, thephpleague) rather than implementing flows manually.

Watch Out

Never implement OAuth flows from scratch — subtle ordering and validation requirements (state, PKCE verifier, redirect_uri exact match, token expiry) are easy to get wrong. Use a maintained library and audit its configuration.

Common Misconception

OAuth 2.0 is an authorisation framework, not an authentication protocol — it proves that a user granted access, not who the user is. Use OpenID Connect (OIDC) on top of OAuth 2.0 for authentication and identity.

Why It Matters

OAuth 2.0 is the foundation of third-party login, API access delegation, and service-to-service auth across the web — misimplementing flows (missing PKCE, open redirects, insecure token storage) leads to account takeover.

Common Mistakes

  • Using Implicit flow instead of Authorization Code + PKCE for SPAs — Implicit was deprecated in OAuth 2.1 because tokens appear in the URL fragment and browser history.
  • Not validating the state parameter on redirect — enables CSRF attacks that bind the attacker's authorisation code to the victim's session.
  • Storing access tokens in localStorage — readable by any JavaScript on the page; prefer HttpOnly cookies or in-memory storage.
  • Not restricting redirect_uri to an exact match — a wildcard or prefix match enables token theft via open redirects.

Code Examples

💡 Note
The bad example skips state validation — an attacker can initiate an OAuth flow, interrupt it, and trick a victim into completing it, binding the attacker's authorisation code to the victim's session. Validating and consuming state before exchanging the code prevents this.
✗ Vulnerable
// Missing state validation — CSRF on OAuth callback:
public function callback(Request $req): Response {
    $code = $req->get('code');
    $token = $this->oauth->getAccessToken('authorization_code', [
        'code' => $code
    ]);
    // No state check — attacker can initiate flow, trick victim into completing it
    Auth::loginWithToken($token);
}
✓ Fixed
// State validated before token exchange:
public function callback(Request $req): Response {
    if ($req->get('state') !== Session::get('oauth_state')) {
        throw new InvalidStateException();
    }
    $code = $req->get('code');
    $token = $this->oauth->getAccessToken('authorization_code', [
        'code' => $code
    ]);
    Session::forget('oauth_state');
    Auth::loginWithToken($token);
}

Added 10 Apr 2026
Views 49
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 1 ping T 3 pings F 0 pings S 1 ping S 2 pings M 2 pings T 1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 2 pings T 0 pings W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 6 Google 5 SEMrush 5 ChatGPT 4 Perplexity 3 Ahrefs 3 Bing 3 Claude 2 Unknown AI 1 Meta AI 1 Majestic 1 PetalBot 1
crawler 33 crawler_json 2
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: High
⚡ Quick Fix
Always use Authorization Code + PKCE for public clients; validate state on every callback; store tokens in HttpOnly cookies not localStorage
🔗 Prerequisites
🔍 Detection Hints
OAuth callback handler missing state parameter validation before getAccessToken()
Auto-detectable: ✗ No semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: High Context: Function Tests: Update
CWE-287 CWE-352 CWE-601


✓ schema.org compliant