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);
}