PKCE

Why PKCE matters and how LoginWith handles it for you.

PKCE (Proof Key for Code Exchange) is an OAuth 2.0 extension that protects against authorization code interception. It’s mandatory for public clients (SPAs, mobile apps) and recommended for confidential ones.

Why it exists

Without PKCE, an attacker who intercepts the authorization code in the redirect (say, via a malicious app registered for the same URL scheme, or a network MITM on an imperfectly-HTTPS’d flow) can exchange it for a token — no client secret required for public clients. PKCE binds the code exchange to a secret that only the original requester holds.

The dance

  1. Before redirecting to the auth server, the client generates a random code_verifier (43–128 chars of base64url).
  2. It computes code_challenge = base64url(sha256(code_verifier)) and stashes the verifier somewhere it can retrieve later.
  3. The redirect includes code_challenge and code_challenge_method=S256.
  4. The auth server remembers the challenge keyed by the issued authorization_code.
  5. When the client exchanges the code for a token, it must also send the code_verifier. The auth server SHA-256s it and compares against the stored challenge. Match → token. Mismatch → rejection.

What LoginWith handles

The SDK does all of this:

  • Generates the verifier (cryptographically random, 43 chars of base64url).
  • Stores it — in localStorage for SPAs, in a signed httpOnly cookie for the server-assisted SSR path.
  • Computes the challenge and bakes it into the authorize URL.
  • On the callback, retrieves the verifier and includes it in the token exchange.

You never have to touch any of it. The manual section on the landing page walks through what the SDK replaces for you — it’s ~10 steps of bash + openssl.

Storage trade-offs

Your options:

  • localStorage (SPA default): simple, industry norm (Auth0, Okta, MSAL all do this). Accepts XSS as game-over.
  • httpOnly cookie (SSR): verifier lives server-side, never touches client JS. Requires a server endpoint you control.
  • Session storage: scoped to the tab. Same XSS exposure as localStorage but shorter-lived.

For real XSS resistance, your mitigations are strict CSP + output encoding + no untrusted scripts — not storage choice. See the SDK pages for how to pick.