Authorization Code Flow with PKCE

The OAuth flow for apps that cannot keep a secret: the client proves it started the login with a one-time hash, so a stolen code is useless.

PKCEpixiethe safe OAuth flowwhy my SPA login brokecode verifier and code challengeOAuth without a client secretauth code flow for mobile appsPKSE

See it

Live demo coming soon

What it is

Proof Key for Code Exchange (RFC 7636, said out loud as 'pixie') is the authorization code flow hardened for clients that cannot keep a secret: single-page apps, mobile apps, desktop apps, CLIs. Before redirecting, the client generates a random code_verifier, sends its SHA-256 hash as the code_challenge with method S256, and later must present the original verifier to redeem the code. An attacker who intercepts the authorization code (via a hijacked custom URL scheme, a leaky referrer, browser history) cannot exchange it, because they never had the verifier.

This is now the default answer for browser and native logins. The implicit flow, which returned tokens straight in the URL fragment, is deprecated, and that is usually what people mean when they say their SPA login 'broke' after a library upgrade. Backend web apps that can hold a client secret should still use the code flow, and adding PKCE there is recommended anyway.

Gotcha: PKCE proves the code came back to the same client instance, not that the request came from the right page. You still need the state parameter for CSRF, and a nonce if you want ID token replay protection. Two other traps: use S256 rather than 'plain', and register redirect URIs exactly, since a loose wildcard undoes the whole thing.

Ask AI for it

Implement OAuth 2.0 authorization code flow with PKCE for this app as a **public client**: a single-page, mobile, or desktop app with no backend of its own, where the browser or device holds the verifier and calls the token endpoint itself. Generate a cryptographically random code_verifier (43 to 128 chars) plus a base64url SHA-256 code_challenge with code_challenge_method=S256, and a random state and nonce. Store the verifier and state in sessionStorage, redirect to /authorize, verify state on callback, then POST to /token with code + code_verifier and no client secret. Keep tokens out of localStorage where possible, and do not use the implicit flow. If this app does have a server you control, prefer the backend-for-frontend shape instead: keep the verifier, the token exchange, and the tokens on the server, and give the browser only a session cookie. Pick one architecture and say which, because the two split the same flow differently.

You might have meant

oauth 2 0openid connectoauth state parameteroauth redirect uri callback urlclient id and client secret

Go deeper