The implicit flow exposed access tokens in the URL, and the IETF security BCP removed it from the recommended set in RFC 9700 (2025). For public clients, SPAs and mobile apps, you implement authorization code with PKCE and validate every ID token claim before you trust user data. This post walks the flow and the bills production sends.
The roles and what each one holds
OAuth separates four roles: the resource owner is the user, the client is your application, the authorization server issues tokens, and the resource server protects the API. Public clients hold no secret, which is why PKCE exists. The redirect URI is registered at the authorization server with exact comparison; a wildcard URI opens an open redirect, and an attacker captures the code on the way back.
You test the redirect with a different port, a lookalike subdomain, and a relative path. RFC 9700 (IETF, 2025) lists redirect URIs with weak validation among the token interception vectors.
The PKCE flow, step by step
You generate a random code_verifier, compute its SHA-256 hash, and send the code_challenge with the authorization request. The authorization server stores the challenge. When you exchange the code for tokens, you send the verifier and the server compares the two. RFC 7636 (IETF, 2015) describes the pair. An attacker who intercepts the code on the device holds no verifier, so the exchange fails. jwt-autenticacao-completa" class="post-internal-link">Refresh tokens rotate: the server issues a new refresh token on every use and invalidates the previous one; detected reuse revokes the whole family.
ID token is not an access token
OIDC layers on top of OAuth and adds the ID token, a JWT signed by the authorization server. The access token protects the API; the ID token authenticates the user at the client. Before you read name, email, or email_verified, you validate the signature, iss, aud and nonce against the server's discovery document. OpenID Connect Core 1.0 (OpenID Foundation, 2014) defines the split between the two tokens.
Production pitfalls
An SPA that stores access tokens in localStorage hands XSS a free path: an injected script reads the key and calls the API as you. The BFF (Backend for Frontend) pattern keeps the session in an httpOnly cookie while the backend speaks OAuth with the authorization server. Sessions end with RP-initiated logout: the client asks the server to terminate the session and redirects the user back. Your security suite runs every endpoint with an expired token, a token from another client, and a token without scope; authorization holes show up in those three tests.
Enjoyed this content?
I build web products and AI solutions the right way — solid architecture, maintainable code, and real delivery.
Let's talk