Engineer's toolkit
OAuth and OpenID Connect
OAuth 2.0 delegates access to a third-party app. OpenID Connect adds a login identity on top. The authorization code flow with PKCE is the safe default.
OAuth 2.0 answers "may this app act for this user?" It issues an access token that names the scopes the app may use. It was never designed to say who the user is. OpenID Connect (OIDC) adds that: an ID token that is a signed JWT naming the user, delivered through the same flow. "Sign in with Google" is OIDC built on OAuth.
Three roles appear in every flow: the user, the client app that wants access, and the authorization server (Google, Okta, Auth0, or your own identity provider) that issues the tokens.
The big idea
The safe flow is the authorization code flow with PKCE. The browser never sees an access token. The browser gets a short-lived code through a redirect, and the app's backend trades the code for tokens directly with the authorization server, over a back channel.
Why the detour? Anything in the browser's address bar can leak, including history, logs and other scripts. A code that can be used only once, by the app that started the flow, is much less useful to an attacker.
Walking through it
PKCE (Proof Key for Code Exchange) protects against a stolen code. Before the redirect, the app makes a random code_verifier and sends its hash, the code_challenge. At the token request, it sends the original verifier. An attacker who intercepts the code can't redeem it without the verifier.
code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
code_challenge = BASE64URL(SHA256(code_verifier))
= E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cMThose values are the example from RFC 7636. Your app generates a new verifier for every login.
Three checks guard the redirect:
stateis a random value the app sends and then checks on return. It stops login CSRF, where an attacker finishes their login in your browser.redirect_urimust match a registered value exactly. Partial or prefix matching lets an attacker send the code to their own server.noncegoes into the ID token. The app checks that it matches, so a replayed ID token fails.
Then, before trusting the ID token, validate it as a JWT: the signature against the provider's published keys, iss, aud (your client ID), and exp. This is the same discipline covered in JWTs and token validation.
Which flows to avoid
The implicit flow returned tokens in the URL fragment, directly to the browser. Current guidance (RFC 9700) says to stop using it. The resource owner password grant asks the client to collect the user's password, which breaks the point of delegation. Use the code flow with PKCE for every client, including single-page apps and mobile apps.
Common mistakes
- Using the implicit flow, or the password grant, in new code.
- Accepting any
redirect_urithat starts with your domain. - Treating an OAuth access token as proof of identity. Use the ID token for identity and the access token for APIs.
- Skipping the
stateornoncechecks because the happy path works.
Check yourself
- Why does PKCE stop a stolen authorization code from being useful?
Answer: redeeming the code needs the original
code_verifier, which never went through the browser redirect. - Why does OIDC add an ID token when OAuth already has an access token? Answer: the access token grants API access and isn't meant to identify the user. The ID token names the user and is meant for the client app.
Key takeaways
- OAuth delegates access. OIDC adds login identity through an ID token.
- Use the authorization code flow with PKCE for every client.
- Check
state,nonce, the exactredirect_uri, and the ID token's signature, issuer, audience and expiry. - Don't use the implicit flow or the password grant.
Further learning
The OAuth 2.0 Security Best Current Practice (RFC 9700) is the current list of required defenses.
RFC 9700: OAuth 2.0 Security Best Current PracticeThis document describes best current security practice for OAuth 2.0. It updates and extends the threat model and security advice given in RFCs 6749, 6750, and 6819 to incorporate practical experiences gathered since …rfc-editor.orgNext, see how the identity you now have is checked against permissions in authorization models and IDOR.
Related
Authentication and authorization
Authentication proves who you are, authorization decides what you can do, and service-to-service calls need their own identity. The map for the rest of this topic.
JWTs and token validation
A JWT is a signed claim set, not a secret. How to validate one safely, the alg confusion and none attacks, and when a JWT is the wrong tool.
IAM and least privilege
How cloud identity works, why least privilege is a habit rather than a checkbox, and where the org-level guardrails sit. Start here for the map of IAM pages.