Authorization Code Grant — The Standard OAuth2 Flow for Web Applications
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
- User credentials stay between user and authorization server
- The authorization code is temporary (1-2 minute lifetime)
- Code exchange requires client_secret (confidential client)
- 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
- What is the purpose of the authorization code?
- Why must the code exchange happen server-side?
- How does the state parameter prevent CSRF?
- Why should authorization codes have short lifetimes?
- What happens during the code exchange step?
Answers:
- The authorization code is a temporary credential that proves the user authorized the request. It is exchanged for tokens.
- The code exchange requires the client_secret, which must be kept confidential. A server-side exchange protects this.
- The client generates a unique state, includes it in the auth request, and verifies it in the callback. An attacker cannot guess the state.
- If the code is intercepted, the short lifetime prevents the attacker from exchanging it for tokens.
- 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
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