100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

The Authorization Code Flow

A step-by-step walkthrough of OAuth 2.0's most widely used grant type, the authorization code flow, including why PKCE is now required for public clients.

FoundationsIntermediate10 min readJul 10, 2026
Analogies

The Authorization Code Flow

The authorization code flow is the most widely used and most secure OAuth 2.0 grant type, recommended for essentially every scenario where a user is present in a browser: traditional server-rendered web apps, single-page apps, and native/mobile apps. Its defining feature is a two-step token exchange — the browser first receives a short-lived, single-use authorization code, and only then does a separate, harder-to-intercept request (ideally from a confidential backend) trade that code for the actual access and refresh tokens.

🏏

Cricket analogy: It's like a two-step ticketing system where the stadium first hands you a voucher at the fan zone, and only later, at a separate, staffed booth, do you exchange that voucher for the actual seat ticket — a lost voucher alone can't get someone into the ground.

Step-by-Step Walkthrough

The flow begins when the client redirects the user's browser to the authorization server's /authorize endpoint with query parameters: response_type=code, its client_id, the redirect_uri, one or more scope values, and a random state value. At this point the authorization server takes over: if the user isn't already logged in it shows a login form, and either way it then shows a consent screen listing exactly what the requesting app wants to do, letting the user approve or deny.

🏏

Cricket analogy: This is like a fan clicking 'request pass' on a franchise's app, being redirected to the franchise's own official ticketing site to log in, and then seeing an explicit approval screen listing exactly what the pass will allow, before anything is granted.

If the user approves, the authorization server redirects the browser back to the registered redirect_uri, appending code=<authorization_code> and the same state value the client sent originally. The client must verify that the returned state matches what it generated before the redirect — this is the CSRF check — and the authorization code itself is deliberately short-lived (often 30-60 seconds) and single-use, so even if it's somehow observed in browser history or a referrer header, an attacker has a very small window and only one shot to use it.

🏏

Cricket analogy: The single-use, short window is like a boundary-rope access token valid for exactly one specific over — even if someone glimpses it, by the time they act on it, the over (and its validity) is already over.

Finally, the client's backend makes a direct, server-to-server POST request to the /token endpoint, sending the authorization code, its client_id, client_secret (for confidential clients), and redirect_uri again for verification. The authorization server checks all of this, confirms the code hasn't already been used or expired, and responds with the access token, an optional refresh token, and the token's expiration — this backend-to-backend leg never touches the user's browser, which is precisely why it's considered the secure half of the exchange.

🏏

Cricket analogy: This final exchange is like the production truck's engineers privately confirming credentials with the ground's control room over a dedicated, non-public line — not something that happens in view of the crowd or over the public PA system.

http
# Step 1: Redirect the browser (client-side, e.g. in a link or JS redirect)
GET https://auth.example.com/authorize
    ?response_type=code
    &client_id=blog_app_42
    &redirect_uri=https://blog.example.com/oauth/callback
    &scope=openid%20profile%20posts.write
    &state=aZ9x2Klp

# Step 2: Authorization server redirects back after user approves
HTTP/1.1 302 Found
Location: https://blog.example.com/oauth/callback?code=4/0AY0e-g7...&state=aZ9x2Klp

# Step 3: Backend exchanges the code for tokens (server-to-server)
curl -X POST https://auth.example.com/token \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'grant_type=authorization_code' \
  -d 'code=4/0AY0e-g7...' \
  -d 'redirect_uri=https://blog.example.com/oauth/callback' \
  -d 'client_id=blog_app_42' \
  -d 'client_secret=SUPER_SECRET_VALUE'

# Response
{
  "access_token": "ya29.a0AfH6...",
  "id_token": "eyJhbGciOi...",
  "refresh_token": "1//0gLhq...",
  "token_type": "Bearer",
  "expires_in": 3599
}

Why PKCE Matters for Public Clients

Mobile apps and single-page apps are 'public clients' — they cannot keep a client_secret confidential, since anyone can decompile the app binary or inspect the browser's JavaScript bundle. For these clients, RFC 7636 defines PKCE (Proof Key for Code Exchange): before redirecting, the client generates a random code_verifier, hashes it into a code_challenge, and sends only the challenge in the authorization request; when exchanging the code, it sends the original verifier, and the authorization server checks the hash matches — meaning even if an attacker intercepts the authorization code, they can't redeem it without the verifier that only the legitimate client generated.

🏏

Cricket analogy: PKCE is like a fan generating a secret number at home, submitting only its hash when requesting a ticket voucher, and later revealing the original number to redeem the actual ticket — a scalper who intercepts the voucher alone still can't redeem it without that original secret.

As of current OAuth 2.0 best current practice (RFC 9700), PKCE is recommended for ALL clients, not just public ones — including confidential server-side apps — because it adds defense-in-depth against authorization code injection attacks at essentially no cost.

The implicit grant (response_type=token), which returned access tokens directly in the URL fragment with no code exchange step, is now deprecated and explicitly discouraged by the OAuth 2.0 Security Best Current Practice. Use the authorization code flow with PKCE instead, even for single-page apps.

  • The authorization code flow is a two-step exchange: a short-lived code first, then a separate token exchange.
  • The client redirects to /authorize with response_type=code, client_id, redirect_uri, scope, and state.
  • The authorization server owns login and consent; approval redirects back with the code and the original state.
  • Authorization codes are short-lived and single-use, minimizing the risk of interception.
  • The code-to-token exchange happens server-to-server via POST to /token, never exposed to the browser.
  • PKCE (RFC 7636) protects public clients by requiring proof of a locally generated secret to redeem the code.
  • The implicit grant is deprecated; use authorization code + PKCE for all client types today.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#OAuth20StudyNotes#TheAuthorizationCodeFlow#Authorization#Code#Flow#Step#Security#StudyNotes#SkillVeris