OAuth 2.0 Flows Explained

OAuth 2.0 delegates access. A user grants an app a limited token to act on their behalf, without sharing the password. Different flows for different client types.

1 credit

The flows

6 items
Authorization Code + PKCE
The right default. SPAs, mobile, server apps. User-agent redirect + one-time code exchanged for token.
Authorization Code (classic)
Server apps with a client secret. Same as above, no PKCE. Use PKCE version for new builds.
Client Credentials
Server-to-server, no user involved. Your backend → vendor API.
Device Code
Input-constrained devices (TV, CLI). User opens a URL on their phone, enters a code.
Implicit (deprecated)
Token in URL fragment. Don't use. Superseded by Auth Code + PKCE.
Password (deprecated)
User types pwd into 3rd-party app. Negates the whole point of OAuth.

Token types

  • **Access token** — short-lived (5-60 min), sent with each API call (`Authorization: Bearer <token>`).
  • **Refresh token** — long-lived, stored securely, exchanged for new access tokens. Rotate on every use when possible.
  • **ID token (OIDC)** — JWT about the user (who they are). OAuth alone doesn't prove identity; OpenID Connect layers that on top.

Scopes

  • Request the minimum needed — `read:profile` beats `full_access`.
  • Show the user what they're granting before redirect.
  • Verify scope server-side on every request — the token tells you what it's allowed to do.

Implementation tips

  • Use a library (`@auth/core`, Hydra, Auth0, Clerk, Keycloak). Don't implement the redirect-validate-exchange dance yourself.
  • State parameter prevents CSRF on the callback — always set and verify.
  • Redirect URIs must exactly match what's registered (incl. trailing slash). Most "mismatch" errors are this.
  • HTTPS in production. `localhost` is the only non-HTTPS exemption most providers allow.

Further reading