Overview
This post explains the complete OIDC Authorization Code flow when a user logs in via an external IdP (like Google) through Cognito User Pool.
The Complete Flow
┌──────────┐ ┌─────────────┐ ┌─────────────────┐ ┌──────────┐
│ Browser │ │ Your App │ │ Cognito │ │ Google │
│ │ │ (Backend) │ │ User Pool │ │ IdP │
└────┬─────┘ └──────┬──────┘ └────────┬────────┘ └────┬─────┘
│ │ │ │
│ 1. Click "Login with Google" │ │
│──────────────────>│ │ │
│ │ │ │
│ 2. Redirect to Cognito │ │
│<──────────────────│ │ │
│ │ │ │
│ 3. Browser goes to Cognito /oauth2/authorize │
│─────────────────────────────────────────>│ │
│ │ │ │
│ 4. Cognito redirects to Google │ │
│<─────────────────────────────────────────│ │
│ │ │ │
│ 5. Browser goes to Google login │ │
│───────────────────────────────────────────────────────────────>│
│ │ │ │
│ 6. User enters credentials │ │
│───────────────────────────────────────────────────────────────>│
│ │ │ │
│ 7. Google redirects with code │ │
│<───────────────────────────────────────────────────────────────│
│ │ │ │
│ 8. Browser goes to Cognito /oauth2/idpresponse │
│─────────────────────────────────────────>│ │
│ │ │ │
│ │ 9. Cognito exchanges code with Google │
│ │ │───────────────────>│
│ │ │<───────────────────│
│ │ │ │
│ │ 10. Cognito validates Google's tokens │
│ │ 11. Cognito creates/updates user │
│ │ 12. Cognito generates its own auth code │
│ │ │ │
│ 13. Cognito redirects with Cognito code │ │
│<─────────────────────────────────────────│ │
│ │ │ │
│ 14. Browser goes to your app /callback │ │
│───────────────────> │ │
│ │ │ │
│ │ 15. App exchanges Cognito code for tokens │
│ │─────────────────────>│ │
│ │<─────────────────────│ │
│ │ │ │
│ 16. App stores tokens, user logged in │ │
│<──────────────────│ │ │
Step-by-Step Details
Step 3: Browser to Cognito
GET https://your-domain.auth.us-east-1.amazoncognito.com/oauth2/authorize
?client_id=abc123clientid
&response_type=code
&scope=openid email profile
&redirect_uri=https://yourapp.com/callback
&identity_provider=Google
| Parameter | Purpose |
|---|---|
client_id | Your Cognito App Client ID |
response_type=code | Request authorization code (not tokens directly) |
scope | What user info to request |
redirect_uri | Where Cognito sends user after authentication |
identity_provider | Skip Cognito hosted UI, go directly to Google |
Step 5: Browser to Google
GET https://accounts.google.com/o/oauth2/v2/auth
?client_id=google-client-id.apps.googleusercontent.com
&response_type=code
&scope=openid email profile
&redirect_uri=https://your-domain.auth.us-east-1.amazoncognito.com/oauth2/idpresponse
&state=xyz789
Note: redirect_uri points back to Cognito, not your app.
Step 8: Google redirects to Cognito
GET https://your-domain.auth.us-east-1.amazoncognito.com/oauth2/idpresponse
?code=google-auth-code-xyz
&state=xyz789
Step 9: Cognito exchanges code with Google (server-to-server)
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=google-auth-code-xyz
&client_id=google-client-id.apps.googleusercontent.com
&client_secret=google-client-secret
&redirect_uri=https://your-domain.auth.../oauth2/idpresponse
Google responds:
{
"access_token": "ya29...",
"id_token": "eyJhbG...",
"refresh_token": "1//...",
"expires_in": 3600
}
Steps 10-12: Cognito internal processing
- Validate Google’s ID token: Fetch Google’s JWKS, verify signature, check
audmatches Cognito’s Google client ID - Create/update user: Map Google claims to Cognito attributes, create user if first login
- Generate Cognito’s auth code: A new code for your app to exchange
Step 14: Cognito redirects to your app
GET https://yourapp.com/callback
?code=cognito-auth-code-abc
Step 15: Your app exchanges Cognito code
POST https://your-domain.auth.us-east-1.amazoncognito.com/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=cognito-auth-code-abc
&client_id=abc123clientid
&client_secret=your-cognito-client-secret
&redirect_uri=https://yourapp.com/callback
Cognito responds:
{
"access_token": "eyJraWQ...",
"id_token": "eyJraWQ...",
"refresh_token": "eyJjdHk...",
"token_type": "Bearer",
"expires_in": 3600
}
Two Separate OIDC Flows
| Flow | Client | IdP | Tokens Received |
|---|---|---|---|
| Flow A | Cognito | Google’s tokens (used internally by Cognito) | |
| Flow B | Your App | Cognito | Cognito’s tokens (what your app uses) |
Your app never sees Google’s tokens—only Cognito’s.
Two Authorization Codes
- Google’s code → Cognito exchanges at Google’s
/tokenendpoint - Cognito’s code → Your app exchanges at Cognito’s
/tokenendpoint
What Cognito’s ID Token Contains
{
"iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_XXXXXXXX",
"aud": "abc123clientid",
"sub": "12345678-1234-1234-1234-123456789012",
"email": "user@gmail.com",
"identities": [
{
"providerName": "Google",
"userId": "google-user-id-123",
"providerType": "Google"
}
],
"token_use": "id"
}
| Claim | Meaning |
|---|---|
iss | Cognito User Pool URL (not Google) |
aud | Your Cognito App Client ID |
sub | Cognito’s user ID (not Google’s) |
identities | Shows which external IdP the user came from |
Where Each Secret Lives
| Secret | Where Configured | Used By |
|---|---|---|
| Google Client ID | Cognito → Federation → Google | Cognito (to redirect to Google) |
| Google Client Secret | Cognito → Federation → Google | Cognito (to exchange code) |
| Cognito App Client ID | Your app’s config | Your app (to call Cognito) |
| Cognito App Client Secret | Your app’s config | Your app (to exchange code) |
Why Two Flows?
This architecture provides:
- Abstraction: Your app only talks to Cognito, regardless of which IdP the user chose
- Unified tokens: Same token format whether user logged in with Google, Facebook, or username/password
- User management: Cognito maintains user records, linking external identities
- Security: Google credentials (client secret) stay in Cognito, not in your app