oauth2-pkce-spa-security.md
OAuth2 + PKCE: Auth for Modern Single-Page Apps
Why implicit flow died, how PKCE protects public clients, and the token flow every React app should implement.
- Security
- OAuth
- Web
SPAs can't keep secrets โ your client ID lives in bundled JavaScript. OAuth2's implicit flow treated that as acceptable. It wasn't. PKCE fixed public client auth without a backend holding credentials.
The actors
- Resource owner โ the user
- Client โ your SPA or mobile app
- Authorization server โ issues tokens (Auth0, Keycloak)
- Resource server โ your API
Authorization code + PKCE flow
- Generate random
code_verifier(43โ128 chars) - Hash it โ
code_challenge(S256) - Redirect user to auth server with challenge
- User logs in, auth server returns authorization code
- Exchange code + original verifier for tokens
// Step 1 โ before redirect
const verifier = generateRandomString(64);
const challenge = base64url(sha256(verifier));
sessionStorage.setItem("pkce_verifier", verifier);
// Step 5 โ token exchange
const res = await fetch("/oauth/token", {
method: "POST",
body: new URLSearchParams({
grant_type: "authorization_code",
code,
code_verifier: sessionStorage.getItem("pkce_verifier"),
client_id: CLIENT_ID,
redirect_uri: REDIRECT_URI,
}),
});An attacker intercepting the code can't exchange it without the verifier they never saw.
Token storage
| Storage | XSS risk | Refresh |
|---|---|---|
| localStorage | High | Easy |
| memory | Lower | Lost on refresh |
| httpOnly cookie | Lowest | Needs BFF pattern |
For SPAs, Backend-for-Frontend (BFF) holding refresh tokens in httpOnly cookies is the production-grade pattern.
What to avoid
Implicit flowโ deprecated (RFC 9700)- Long-lived access tokens in localStorage
- Client secrets in frontend bundles
[!WARNING] OAuth2 is a framework, not a plug-and-play library. Misconfigured redirect URIs and scopes cause more breaches than crypto breaks.
Takeaway
PKCE turns "public client" from a vulnerability into a defined threat model. Pair it with short-lived access tokens and secure refresh handling โ your users (and compliance team) will thank you.
Related
Continue reading
More notes on similar topics.
A living reference for writing posts โ thumbnails, code, tables, alerts, footnotes, images, audio, video, and YouTube embeds.
- Markdown
- Blog
How Ken Perlin's gradient noise creates infinite terrain, clouds, and fire โ and why Simplex improved it thirty years later.
- Graphics
- Algorithms
A frontend engineer's guide to the architecture behind GPT โ self-attention, positional encoding, and the encoder-decoder split.
- ML
- Transformers