Skip to content

Authorization Code Grant — The Standard OAuth2 Flow for Web Applications

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Authorization Code Grant. We cover key concepts, practical examples, and best practices to help you master this topic.

The Authorization Code grant is the most secure OAuth2 flow, where the client receives a temporary code after user authorization and exchanges it for tokens on the server side.

What You'll Learn

How the Authorization Code flow works end-to-end, why it is the recommended grant for web apps, and how to implement it securely.

Why It Matters

This is the most commonly used OAuth2 grant. Every "Login with Google" on a website uses Authorization Code. Understanding it is fundamental to working with modern authentication.

Real-World Use

GitHub OAuth, Google Sign-In, Facebook Login — all use the Authorization Code grant for web applications. The user authorizes in their browser, and the server exchanges the code in a secure backchannel.

sequenceDiagram
    participant User
    participant App as Web App (Client)
    participant Auth as Authorization Server
    participant API as Resource Server

    User->>App: Click "Login"
    App->>Auth: Redirect to /authorize
    User->>Auth: Authenticate + consent
    Auth->>App: Redirect with code
    App->>Auth: POST /token (code + secret)
    Auth->>App: Access Token + Refresh Token
    App->>API: GET /data (Bearer Token)
    API->>App: Protected Data
    App->>User: Show Page

Why Authorization Code Is Secure

  1. User credentials stay between user and authorization server
  2. The authorization code is temporary (1-2 minute lifetime)
  3. Code exchange requires client_secret (confidential client)
  4. The state parameter prevents CSRF Attacks

Code Example: Authorization Code Flow

from flask import Flask, request, redirect, jsonify
import requests, secrets

app = Flask(__name__)

CLIENT_ID = "your-client-id"
CLIENT_SECRET = "your-client-secret"
REDIRECT_URI = "https://yourapp.com/callback"
AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth"
TOKEN_URL = "https://oauth2.googleapis.com/token"

@app.route("/login")
def login():
    state = secrets.token_urlsafe(32)
    # Store state in session for verification
    params = {
        "response_type": "code",
        "client_id": CLIENT_ID,
        "redirect_uri": REDIRECT_URI,
        "scope": "openid email profile",
        "state": state,
        "access_type": "offline"
    }
    auth_url = f"{AUTH_URL}?{requests.compat.urlencode(params)}"
    return redirect(auth_url)

@app.route("/callback")
def callback():
    code = request.args.get("code")
    state = request.args.get("state")

    if not code:
        error = request.args.get("error", "unknown")
        return f"Authorization failed: {error}", 400

    # Verify state (prevent CSRF)
    # Compare with state stored in session

    # Exchange code for tokens
    token_response = requests.post(TOKEN_URL, data={
        "grant_type": "authorization_code",
        "code": code,
        "redirect_uri": REDIRECT_URI,
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET
    })

    if token_response.status_code != 200:
        return "Token exchange failed", 400

    tokens = token_response.json()
    return jsonify({
        "access_token": tokens["access_token"][:20] + "...",
        "refresh_token": tokens.get("refresh_token", "none")[:20] + "...",
        "expires_in": tokens["expires_in"]
    })

Common Mistakes

1. Not Using State Parameter

Without state, CSRF attacks can swap the authorization code. Always generate a unique, unguessable state and verify it.

2. Long Authorization Code Lifetime

Codes should expire within 1-2 minutes. A code intercepted later is useless.

3. Exposing Client Secret in Frontend

The client_secret is for the backend only. If included in JavaScript, anyone can read it.

4. Not Validating redirect_uri

The authorization server must validate the redirect_uri. Otherwise, attackers can use open redirectors.

5. Storing Access Tokens in Browser History

The access token is returned in the callback response. Never log it or store it in the URL.

Practice Questions

  1. What is the purpose of the authorization code?
  2. Why must the code exchange happen server-side?
  3. How does the state parameter prevent CSRF?
  4. Why should authorization codes have short lifetimes?
  5. What happens during the code exchange step?

Answers:

  1. The authorization code is a temporary credential that proves the user authorized the request. It is exchanged for tokens.
  2. The code exchange requires the client_secret, which must be kept confidential. A server-side exchange protects this.
  3. The client generates a unique state, includes it in the auth request, and verifies it in the callback. An attacker cannot guess the state.
  4. If the code is intercepted, the short lifetime prevents the attacker from exchanging it for tokens.
  5. The client sends the code, client_id, client_secret, and redirect_uri to the token endpoint. The auth server validates these and returns tokens.

Challenge: Implement the full Authorization Code flow with state parameter, short-lived code enforcement, and secure token storage. Test with a real OAuth2 provider.

FAQ

What is the difference between response_type=code and response_type=token?

response_type=code requests an authorization code (Authorization Code grant). response_type=token directly returns an access token (Implicit grant, deprecated).

Can Authorization Code be used without PKCE?

For confidential clients (web apps with backend), yes. For public clients (mobile, SPA), use PKCE.

How long should the state parameter be?

At least 128 bits (32 bytes) from a cryptographically secure random generator. secrets.token_urlsafe(32).

What if the user denies authorization?

The auth server redirects back with an error parameter (access_denied). The client should handle this gracefully.

Does Authorization Code support MFA?

Yes. Since the user authenticates directly with the authorization server, MFA challenges work naturally.

Mini Project

Build a Flask web app implementing the Authorization Code flow: login redirect, callback handler with state verification, code exchange, and display of returned token data.

What's Next

Now learn about the Implicit Grant (Deprecated) — why it was deprecated and what to use instead.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro