reference guide

OAuth 2.0 Flow Reference

Every grant type — sequence diagrams, pros, cons, and when to use each. Click any card to expand.

at a glance
Flow User login Browser needed Secret in browser Status
Authorization Codeyesyesnostandard
Auth Code + PKCEyesyesnorecommended
ROPCyesnonofirst-party only
Client Credentialsnononostandard
Device Authorizationyesseparate devicenostandard
Implicityesyestoken in URLdeprecated
Refresh Tokensub-flowstandard
Token Exchangesub-flowstandard
detailed breakdown
01 / 08
Authorization Code
Classic server-side flow. client_secret lives on the server, never in the browser.
user login browser redirect server-side secret
+
pros
  • client_secret stays on server — never exposed
  • short-lived code limits interception window
  • supports refresh tokens for long sessions
  • widely supported by all providers
cons
  • requires a backend server to hold the secret
  • full page redirect — not seamless for SPAs
  • more round trips than simpler flows
  • not suitable for SPAs without a backend
use cases
  • Traditional web apps (Rails, Django, Express)
  • Apps with a backend that stores secrets securely
  • "Login with Google/GitHub" on server-rendered apps
Authorization Code flow sequence Browser App server Auth server GET /dashboard 302 → /authorize?client_id&state GET /authorize (user logs in on auth server) 302 → /callback?code=ABC&state=XYZ GET /callback?code=ABC secret stays here POST /token {code, client_id, client_secret} {access_token, refresh_token} session cookie code is single-use · expires in ~5 min · secret never leaves the server
02 / 08
Authorization Code + PKCE
Auth Code without a static secret. Standard for all browser and mobile apps.
user login browser redirect no static secret
+
pros
  • no static client_secret needed in browser
  • intercepted code is useless without verifier
  • recommended for all public clients
  • fully standardised — RFC 7636
cons
  • still requires redirect + auth server login page
  • slightly more complex than ROPC
  • verifier must be generated fresh per session
  • overkill for internal first-party-only apps
use cases
  • Single-page apps (React, Vue, Angular)
  • Mobile apps (iOS, Android)
  • Any public client that can't hold a secret
  • Third-party OAuth integrations in the browser
PKCE flow sequence React admin Admin API Auth server generate verifier + challenge GET /authorize?code_challenge&client_id → user logs in redirect → /callback?code=ABC&state POST /callback {code, verifier} POST /token {code, verifier, client_id} SHA256(verifier) == challenge ✓ {access_token, refresh_token} GET /userinfo Bearer token {user_id, email, roles} session cookie verifier generated fresh per login · intercepted code is useless without it
03 / 08
ROPC
Resource Owner Password Credentials. No redirect, no login page. First-party only.
user login no redirect first-party only
+
pros
  • no redirect — embedded login form in your app
  • no separate login page to maintain
  • simplest flow for first-party apps
  • full control over the UX
cons
  • client app handles credentials directly
  • unsafe for any third-party clients
  • hard to add MFA or social login
  • discouraged in OAuth 2.1 spec
use cases
  • Internal admin dashboards you fully own
  • Migration paths from legacy auth systems
  • CLI tools authenticating against your own API
  • First-party mobile apps
ROPC flow sequence React admin Admin API Auth server user types username + password POST /login {username, password} POST /token grant_type=password {access_token, refresh_token} GET /userinfo Bearer token {user_id, email, roles} session cookie no redirect · no login page · safe only because you own both client and server
04 / 08
Client Credentials
Machine-to-machine. No user, no browser. Two services authenticating directly.
no user no browser server-to-server
+
pros
  • simplest possible token flow
  • no user session to manage
  • tokens cacheable until expiry
  • ideal for automated background tasks
cons
  • client_secret must be kept secure on server
  • no user context — all actions are service-level
  • secret rotation requires coordination
  • not suitable when acting on behalf of a user
use cases
  • Cron jobs and background workers
  • Microservices calling other microservices
  • CI/CD pipelines accessing deployment APIs
  • Webhooks and event-driven systems
Client Credentials flow sequence Service A (client) Auth server POST /token {client_id, client_secret, grant_type=client_credentials} {access_token, expires_in} — no refresh token GET /api/resource Bearer access_token 200 data token can be cached and reused until it expires
05 / 08
Device Authorization
Device shows a short code. User authenticates on their phone. Device polls for approval.
user login separate device polling
+
pros
  • works on devices with no browser
  • user authenticates on a familiar device
  • no credentials typed on the limited device
  • supports MFA on the authorising device
cons
  • polling adds latency
  • user_code expires — time pressure on user
  • two-device UX can confuse users
  • not appropriate for normal web apps
use cases
  • Smart TVs and streaming apps
  • CLI tools (GitHub CLI, AWS CLI)
  • IoT devices with limited input
  • Game consoles
Device Authorization flow sequence Device / CLI Auth server User's phone POST /device {client_id} {device_code, user_code, verification_uri} display: visit url + ABCD-1234 visits url + enters user_code + logs in approved ✓ POST /token {device_code} ↻ poll every 5s {access_token, refresh_token} device_code ties the poll to the approval · user_code is short and human-readable
06 / 08
Implicit Flow — deprecated
Token returned directly in the URL fragment. No code exchange. Replaced by PKCE.
user login browser redirect token in URL deprecated
+
pros
  • fewer round trips than Auth Code (historically)
  • simpler for legacy SPAs pre-2019
  • (these no longer apply — use PKCE)
cons
  • token exposed in URL — visible in browser history
  • accessible to any JS on the page (XSS risk)
  • no refresh token issued
  • leaks via Referrer header to third-party resources
  • officially deprecated in OAuth 2.1
use cases
  • Do not use for new applications
  • Legacy SPAs built before ~2019
  • Migration target: replace with PKCE
Implicit flow sequence (deprecated) Browser Auth server GET /authorize?response_type=token&client_id → user logs in 302 → /callback#access_token=XYZ ← TOKEN IN URL FRAGMENT visible in browser history · readable by any JS on page · leaks via Referrer · no refresh token JS reads #access_token DEPRECATED — replace with Authorization Code + PKCE for all browser-based apps
07 / 08
Refresh Token
Silent re-auth when access token expires. User never sees a login prompt.
sub-flow silent session management
+
pros
  • access tokens stay short-lived for security
  • user session persists without re-login
  • transparent to the user
  • rotate on each use for extra security
cons
  • refresh token theft = persistent access
  • must store in httpOnly cookie, not localStorage
  • rotation logic adds implementation complexity
  • revocation needs server-side token store
use cases
  • Any flow that issues a refresh_token
  • Keeping sessions alive for days or weeks
  • Mobile apps running in background
  • Silent token renewal in SPAs
Refresh Token flow sequence Client app Resource API Auth server GET /api/data Bearer valid_token 200 OK access_token expires GET /api/data Bearer expired_token 401 Unauthorized POST /token {refresh_token, grant_type=refresh_token} new {access_token, refresh_token} ← rotate GET /api/data Bearer new_token 200 OK rotate refresh tokens on every use · store in httpOnly cookie · user never prompted
08 / 08
Token Exchange
RFC 8693. Service A exchanges its token for a scoped token to call Service B on behalf of a user.
sub-flow microservices delegation RFC 8693
+
pros
  • user identity preserved across service chain
  • each token scoped only to its target service
  • audit trail follows real user, not just a service
  • no need to pass original token downstream
cons
  • complex — most teams don't need it
  • auth server must understand the audience claim
  • adds latency at each service hop
  • limited library and provider support
use cases
  • Microservice chains acting on a user's behalf
  • API gateways delegating to backend services
  • Zero-trust architectures
  • On-behalf-of flows in enterprise systems
Token Exchange flow sequence User Service A Auth server Service B call with token_A needs to call Service B POST /token {subject_token=token_A, audience=serviceB} validate + scope for Service B token_B (scoped to Service B, same user identity) GET /resource Bearer token_B 200 data response token_B unusable outside Service B · grant_type=urn:ietf:params:oauth:grant-type:token-exchange