A SPA is a public client: it can't keep a secret. So how does it prove that the party
redeeming the authorization code is the same one that started the flow?
PKCE. The app sends a hash (code_challenge) up front and the secret
code_verifier only at token exchange. Toggle PKCE and simulate an attacker who steals the
code. The challenge here is a real SHA-256. live crypto
— run the flow —
PKCE protects the code in transit; it does nothing for where you keep the token afterwards. Pick a storage strategy, then run a simulated XSS payload and see what it can steal. All modeled — the "token" is fake and nothing is sent anywhere.
— run the payload —