Authorization Code Flow
The Authorization Code Flow is the most common OAuth/OIDC flow used by web applications.
This is the flow behind:
- Login with Google
- Login with GitHub
- Login with Microsoft
It is designed to securely authenticate users without exposing credentials to your application.
High-Level Flow
[Your App]
→ Redirect user to Google login
[Google]
→ User logs in and grants permissions
→ Google returns authorization code
[Your Backend]
→ Exchanges code for tokens
→ Verifies ID token
→ Creates session/JWT in your system
At a high level:
- User authenticates with Google
- Google proves identity using tokens
- Your backend establishes its own authenticated session
Step 1 - Redirect User to Provider
Your backend redirects the user to Google’s authorization endpoint.
Example:
https://accounts.google.com/o/oauth2/v2/auth
?client_id=...
&redirect_uri=...
&response_type=code
&scope=openid email profile
Important query parameters:
| Parameter | Purpose |
|---|---|
client_id | Identifies your application |
redirect_uri | Where Google sends the user back |
response_type=code | Enables Authorization Code Flow |
scope | Defines requested permissions |
The openid scope is especially important because it enables OpenID Connect (OIDC). Without openid, you get OAuth authorization only - not authentication. Additional scopes like: email profile allow access to user profile information.
Step 2 - User Logs In & Grants Consent
Google shows:
- login screen
- account selection
- permissions consent screen
After successful authentication, Google redirects the user back to your backend:
redirect_uri?code=XYZ123
The code is a temporary authorization code.
Important properties:
- short-lived
- one-time use
- exchanged server-side for tokens
The code itself is not the final authentication token.
Step 3 - Backend Exchanges Code for Tokens
Your backend sends the authorization code to Google’s token endpoint.
Example request:
POST https://oauth2.googleapis.com/token
Example body:
{
"code": "...",
"client_id": "...",
"client_secret": "...",
"redirect_uri": "...",
"grant_type": "authorization_code"
}
Google responds with tokens:
{
"access_token": "...",
"id_token": "...",
"refresh_token": "...",
"expires_in": 3600
}
Understanding the Tokens
| Token | Purpose |
|---|---|
access_token | Access Google APIs |
id_token | Authenticate the user |
refresh_token | Obtain new access tokens |
Access Token
Used when your app needs to call Google APIs.
Example:
GET https://www.googleapis.com/calendar/v3/...
Authorization: Bearer <access_token>
ID Token
The ID token is the most important token for authentication. It is usually a JWT containing identity information such as:
- user ID (sub)
- issuer
- expiration time
The ID token proves:
“Google successfully authenticated this user.”
Refresh Token
Refresh tokens are long-lived credentials used to obtain new access tokens.
They are typically issued only when:
- offline access is requested
- the provider allows persistent access
PKCE (Proof Key for Code Exchange)
Many providers now require PKCE even for server-side flows. PKCE binds the authorization code to a one-time secret generated by your app, preventing interception attacks.
Step 4 - Backend Verifies ID Token
Your backend must verify the ID token before trusting it.
Verification usually includes:
- verifying the JWT signature
- checking the issuer (iss)
- checking the audience (aud)
- checking expiration (exp)
If verification succeeds: User identity is trusted
This step is critical.
Anyone can decode a JWT, but only properly signed tokens should be accepted as valid.
Step 5 - Backend Creates Its Own Session
Google authenticates the user, but Google does not manage your application’s session system.
Your backend still needs to:
- find or create the user
- create internal user records
- establish authentication state
- issue your own JWT or session cookie
Typical flow:
Google authenticates user
→ Your backend verifies identity
→ Your app creates its own session
This distinction is extremely important.
OAuth/OIDC handles external authentication. Your application still controls sessions, permissions, and authorization.
Why This Flow Is Secure
The Authorization Code Flow is designed so that:
- user credentials never reach your app
- sensitive token exchange happens server-side
- tokens are issued only after successful authentication
- ID tokens can be cryptographically verified
This makes it safer than directly handling user passwords in third-party integrations.