← Concepts

阅读中文版本

OAuth 2.0 Authorization Code Flow with PKCE

The authorization code flow delegates access without sharing passwords. PKCE binds the code exchange to the client, and state protects the redirect from CSRF.

security

Definition

OAuth 2.0 authorization code flow lets a client obtain an access token by redirecting the user to an authorization server, receiving a short-lived code, and exchanging it at the token endpoint. PKCE (Proof Key for Code Exchange) adds a client-generated verifier and a derived challenge so an intercepted code cannot be exchanged by another party. The flow separates the user's credentials from the client and supports refresh tokens and scoped access.

Context and scope

Use this flow for web applications, mobile apps, and single-page apps that need delegated access to an API. The implicit flow, which returned tokens in the URL fragment, is deprecated because tokens leak through browser history and referrers. Confidential server-side clients still use a client secret in addition to PKCE.

Common misconceptions

  • PKCE is only for mobile apps — it protects any public client and is recommended broadly
  • The authorization code is the access token — the code must be exchanged at the token endpoint
  • A redirect URI allowlist is optional — an open redirect can leak codes to an attacker

Anti-patterns

  • Using the implicit flow for new applications
  • Skipping the state parameter, leaving the redirect vulnerable to CSRF
  • Registering wildcard redirect URIs or allowing arbitrary return URLs

Related concepts

Related examples

Authoritative source

https://www.rfc-editor.org/rfc/rfc7636

The flow

  1. The client generates a random code_verifier and its SHA-256 code_challenge.
  2. It redirects the user to the authorization endpoint with client_id, redirect_uri, scope, state, and the challenge.
  3. The user authenticates and consents; the server redirects back with a code and the original state.
  4. The client verifies state and exchanges the code plus the verifier at the token endpoint.
  5. The token endpoint returns an access token and, when allowed, a refresh token.

PKCE in code

const verifier = crypto.randomBytes(32).toString('base64url');
const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');

const authUrl = new URL('https://auth.example.com/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', clientId);
authUrl.searchParams.set('redirect_uri', redirectUri);
authUrl.searchParams.set('scope', 'openid profile');
authUrl.searchParams.set('state', state);
authUrl.searchParams.set('code_challenge', challenge);
authUrl.searchParams.set('code_challenge_method', 'S256');

When to use

Use authorization code + PKCE for delegated API access from browsers, mobile, and server-rendered apps. Compared to embedding credentials in the client, OAuth keeps the password at the authorization server and limits access with scopes and short token lifetimes. Compared to a custom token system, it provides standard flows and interoperable libraries.

Pitfalls

A missing or unchecked state enables login CSRF. A wildcard redirect URI allows codes to be sent to an attacker. Storing tokens in localStorage exposes them to XSS; prefer secure, HttpOnly cookies when the architecture allows. Refresh tokens need rotation and revocation on reuse. Always validate the issuer, audience, and signature of tokens you accept.