AWS Cognito Explained: User Authentication and Authorization for Your Applications
Imagine building a house and having to design and manufacture your own door locks, keys, alarm system, and security cameras from scratch. Every house needs security, but building it yourself is expensive, error-prone, and distracts from the actual house design.
AWS Cognito is like hiring a professional security company. They install the locks (authentication), manage the keys (tokens), set up the alarm (MFA), and handle the guest access (authorization). You just tell them who should have access and what they can do.
Authentication is the most critical and most commonly broken part of any application. Cognito handles it so you do not have to reinvent the wheel — and more importantly, so you do not accidentally leave the front door unlocked.
Table of Contents
- What Is AWS Cognito?
- User Pools vs Identity Pools
- How Authentication Works (The Nightclub Analogy)
- Setting Up a User Pool: Step by Step
- Configuring Sign-Up and Sign-In
- Multi-Factor Authentication (MFA)
- Social Login (Google, Apple, Facebook)
- Hosted UI vs Custom UI
- Tokens Explained: ID, Access, and Refresh
- Integrating Cognito with Your App
- Cognito with React Native (Mobile Apps)
- Cognito with API Gateway (Securing APIs)
- Cognito with AWS Amplify
- User Groups and Role-Based Access
- Lambda Triggers (Custom Logic)
- Account Recovery and Password Policies
- Cognito vs Other Auth Providers
- Pricing
- Common Mistakes
- Interview Questions
- Wrapping Up
What Is AWS Cognito?
AWS Cognito is a fully managed authentication and authorization service. It handles:
- Sign up — user registration with email/phone verification
- Sign in — username/password, social login, SSO
- Token management — JWT tokens for API authorization
- MFA — multi-factor authentication (SMS, TOTP)
- Password policies — minimum length, complexity requirements
- Account recovery — forgot password flows
- User management — admin can create, disable, delete users
- Federated identity — sign in with Google, Apple, Facebook, SAML
You get all of this without building or managing any auth infrastructure.
User Pools vs Identity Pools
Cognito has two components. This confuses everyone at first, so here is the simplest explanation:
User Pool (The Hotel Front Desk)
A User Pool is your user directory. It stores usernames, passwords, emails, phone numbers, and custom attributes. It handles sign-up, sign-in, and token issuance.
Think of it as a hotel front desk. Guests (users) check in (sign up), show their ID (sign in), and receive a room key (token). The front desk knows who every guest is and which room they belong to.
User Pool handles:
- "Who are you?" (authentication)
- Sign up, sign in, forgot password
- Store user profiles
- Issue JWT tokens
- MFA, social login
Identity Pool (The VIP Lounge Access Manager)
An Identity Pool gives authenticated users temporary AWS credentials to access AWS services directly (S3, DynamoDB, etc.).
Think of it as a VIP lounge access system. After checking in at the front desk (User Pool), a VIP guest gets a special bracelet (AWS credentials) that lets them access the pool, spa, and lounge (S3, DynamoDB, Lambda) directly.
Identity Pool handles:
- "What can you access?" (authorization to AWS services)
- Convert Cognito tokens to temporary AWS credentials
- Fine-grained access control (this user can read S3, that user can write DynamoDB)
- Supports unauthenticated (guest) access
When to Use Which
| Scenario | What You Need |
|---|---|
| Web app with login/signup | User Pool only |
| Mobile app with login + file upload to S3 | User Pool + Identity Pool |
| API backend with JWT authentication | User Pool (API Gateway validates tokens) |
| App that needs direct DynamoDB access from frontend | User Pool + Identity Pool |
| Simple app, no AWS service access needed | User Pool only |
Most common pattern: User Pool for authentication + API Gateway for authorization. Identity Pool is only needed when your frontend directly accesses AWS services.
How Authentication Works (The Nightclub Analogy)
Let me explain the entire auth flow using a nightclub analogy:
Step 1: SIGN UP (Getting on the guest list)
User: "Hi, I'm Naveen. Here's my email and password."
Cognito: "Thanks. I'll send you a verification code to confirm your email."
User: "Here's the code: 123456"
Cognito: "Verified. You're on the guest list now."
Step 2: SIGN IN (Showing ID at the door)
User: "Hi, I'm Naveen. Here's my password."
Cognito: "Let me check... yes, you're on the list. Here are your wristbands."
Cognito hands over THREE wristbands (tokens):
- ID Token: "This proves who you are" (name, email, groups)
- Access Token: "This proves what you can do" (permissions, scopes)
- Refresh Token: "Show this to get new wristbands without re-entering" (lasts 30 days)
Step 3: ACCESSING THE API (Getting into VIP)
User shows Access Token to the API bouncer (API Gateway)
API Gateway: "Valid wristband. Come on in."
User gets the data they requested.
Step 4: TOKEN EXPIRED (Wristband expired)
User shows expired Access Token.
API Gateway: "Sorry, this wristband expired."
User shows Refresh Token.
Cognito: "Here are fresh wristbands." (new ID + Access tokens)
User continues without re-entering password.
Step 5: SIGN OUT (Leaving the club)
User: "I'm leaving."
Cognito: "Your wristbands are invalidated. See you next time."
Setting Up a User Pool: Step by Step
Step 1: Create the User Pool
- Go to AWS Console > Amazon Cognito
- Click Create user pool
- Sign-in experience:
- Cognito user pool sign-in options: Email (most common)
- Or: Email + Username, Phone, or custom
- Click Next
Step 2: Security Requirements
- Password policy:
- Minimum length: 8 (or your preference)
- Require: uppercase, lowercase, numbers, special characters
- MFA:
- No MFA (simplest for dev)
- Optional MFA (user can enable)
- Required MFA (enforced for all users)
- Methods: Authenticator app (TOTP) and/or SMS
- Account recovery:
- Email (recommended)
- Click Next
Step 3: Sign-Up Experience
- Self-registration: Enable (users can sign up themselves)
- Attribute verification: Email address
- Required attributes: email (add others as needed: name, phone)
- Custom attributes: You can add custom fields (company, role, plan)
- Click Next
Step 4: Message Delivery
- Email provider: Cognito default (for dev) or Amazon SES (for production)
- Cognito default: limited to 50 emails/day (fine for testing)
- SES: unlimited, custom sender address, production-ready
- Click Next
Step 5: App Integration
- User pool name:
myapp-user-pool - App client:
- Name:
myapp-web-client - Client secret: Don’t generate (for public clients like web/mobile apps)
- Auth flows: ALLOW_USER_SRP_AUTH (secure password), ALLOW_REFRESH_TOKEN_AUTH
- Hosted UI: Enable if you want Cognito’s built-in login page
- Click Next > Create user pool
What You Get
After creation, note these values (you will need them in your app):
User Pool ID: us-east-1_AbCdEfGhI
App Client ID: 1abc2def3ghi4jkl5mno
Region: us-east-1
Configuring Sign-Up and Sign-In
Sign-Up Flow
User enters email + password
--> Cognito validates password policy
--> Cognito sends verification email with 6-digit code
--> User enters the code
--> Account is confirmed and active
Sign-In Flow
User enters email + password
--> Cognito verifies credentials
--> If MFA enabled: sends MFA challenge
--> User enters MFA code
--> Cognito returns 3 tokens (ID, Access, Refresh)
--> App stores tokens securely
--> User is logged in
Customizing Sign-In
You can allow sign-in with: – Email only – Username only – Phone number only – Email OR username (flexible) – Federated providers (Google, Apple) alongside email/password
Multi-Factor Authentication (MFA)
MFA adds a second verification step after the password. Like a bank vault that needs both a key AND a code to open.
TOTP (Authenticator App)
Users scan a QR code with Google Authenticator, Microsoft Authenticator, or similar apps. Each login requires the current 6-digit code from the app.
Pros: Free, no SMS costs, works offline. Cons: User must set up the authenticator app.
SMS
Cognito sends a code via text message.
Pros: Familiar to users, no app required. Cons: Costs per SMS ($0.01-0.05 per message), less secure (SIM swapping attacks).
Adaptive Authentication
Cognito can require MFA only when risk is detected — new device, unusual location, multiple failed attempts. Low-risk logins skip MFA for better user experience.
Real-life analogy: Adaptive MFA is like airport security. Known frequent flyers (trusted devices) go through the fast lane. First-time travelers (unknown devices) get the full screening.
Social Login (Google, Apple, Facebook)
Let users sign in with their existing accounts:
Setting Up Google Sign-In
- Create a Google OAuth 2.0 Client in Google Cloud Console
- Get the Client ID and Client Secret
- In Cognito User Pool > Sign-in experience > Federated identity providers
- Add Google with your Client ID and Secret
- Map attributes: Google email to Cognito email
Setting Up Apple Sign-In
- Create a Service ID in Apple Developer Portal
- Generate a private key for Sign in with Apple
- Add Apple in Cognito with your Service ID, Team ID, and Key
How It Works
User clicks "Sign in with Google"
--> Redirects to Google login page
--> User authenticates with Google
--> Google sends auth code back to your app
--> Your app sends the code to Cognito
--> Cognito exchanges it for Google user info
--> Cognito creates/updates the user in the User Pool
--> Cognito issues its own tokens (ID, Access, Refresh)
--> Your app uses Cognito tokens (NOT Google tokens) for everything
Key point: After social login, your app always uses Cognito tokens, regardless of whether the user signed in with email, Google, or Apple. Your backend does not need to know which method was used.
Hosted UI vs Custom UI
Hosted UI (Quick and Easy)
Cognito provides a pre-built login page:
https://your-domain.auth.us-east-1.amazoncognito.com/login?
client_id=xxxx&
response_type=code&
redirect_uri=https://myapp.com/callback
Pros: Works immediately, handles all edge cases (forgot password, MFA, social login), compliant with OAuth 2.0. Cons: Limited customization (basic CSS only), looks generic.
Real-life analogy: Hosted UI is like a hotel keycard system. It works perfectly but looks the same in every hotel. You cannot customize the keycard reader design.
Custom UI (Full Control)
Build your own login form and call Cognito APIs:
import { signIn, signUp, confirmSignUp } from 'aws-amplify/auth';
// Sign up
await signUp({
username: email,
password: password,
options: { userAttributes: { email, name } }
});
// Confirm sign up
await confirmSignUp({ username: email, confirmationCode: '123456' });
// Sign in
const { isSignedIn, nextStep } = await signIn({ username: email, password });
Pros: Complete design control, matches your brand perfectly. Cons: More code to write, you handle all edge cases.
Real-life analogy: Custom UI is like designing your own front door. You choose the wood, the handle, the peephole. More work, but it matches your house perfectly.
Tokens Explained: ID, Access, and Refresh
Cognito issues three JWT tokens after successful sign-in:
ID Token (Who You Are)
Contains user identity information:
{
"sub": "a1b2c3d4-5678-90ab-cdef-ghijklmnopqr",
"email": "naveen@example.com",
"name": "Naveen Vuppula",
"cognito:groups": ["admin", "data-engineers"],
"exp": 1712700000
}
Use for: Displaying user info in the frontend (name, email, profile picture). Do NOT use for: API authorization (use Access Token instead).
Access Token (What You Can Do)
Contains authorization scopes:
{
"sub": "a1b2c3d4-5678-90ab-cdef-ghijklmnopqr",
"scope": "openid email profile",
"client_id": "1abc2def3ghi",
"token_use": "access",
"exp": 1712700000
}
Use for: Authorizing API requests. Send in the Authorization: Bearer <token> header.
Refresh Token (Stay Signed In)
A long-lived token (default: 30 days) that gets new ID and Access tokens without requiring the user to re-enter their password.
Access Token expired (after 1 hour)
--> App sends Refresh Token to Cognito
--> Cognito returns new ID + Access tokens
--> User stays logged in seamlessly
Real-life analogy: – ID Token = your driver’s license (proves who you are) – Access Token = your gym membership card (proves what you can access) – Refresh Token = your membership renewal form (gets you new cards without re-applying)
Token Lifetimes
| Token | Default Lifetime | Configurable |
|---|---|---|
| ID Token | 1 hour | 5 min to 1 day |
| Access Token | 1 hour | 5 min to 1 day |
| Refresh Token | 30 days | 1 hour to 10 years |
Integrating Cognito with Your App
React Web App (with Amplify)
import { Amplify } from 'aws-amplify';
import { signIn, signOut, getCurrentUser, fetchAuthSession } from 'aws-amplify/auth';
Amplify.configure({
Auth: {
Cognito: {
userPoolId: 'us-east-1_AbCdEfGhI',
userPoolClientId: '1abc2def3ghi4jkl5mno',
loginWith: { email: true }
}
}
});
// Sign in
async function handleSignIn(email, password) {
try {
const { isSignedIn } = await signIn({ username: email, password });
if (isSignedIn) {
console.log('Logged in!');
}
} catch (error) {
console.error('Sign in failed:', error.message);
}
}
// Get current user
const user = await getCurrentUser();
console.log('Username:', user.username);
// Get tokens for API calls
const session = await fetchAuthSession();
const accessToken = session.tokens.accessToken.toString();
// Sign out
await signOut();
Cognito with React Native (Mobile Apps)
Same Amplify library works for mobile:
import { Amplify } from 'aws-amplify';
import { signIn, signUp, signOut } from 'aws-amplify/auth';
// Configure (same as web)
Amplify.configure(config);
// Sign up
await signUp({
username: email,
password: password,
options: { userAttributes: { email, name: fullName } }
});
// Sign in
const result = await signIn({ username: email, password });
// Handle MFA if required
if (result.nextStep.signInStep === 'CONFIRM_SIGN_IN_WITH_TOTP_CODE') {
// Show MFA input screen
}
For iOS App Store: If your app supports third-party login (Google), Apple requires you to also offer Sign in with Apple. Cognito supports this natively.
Cognito with API Gateway (Securing APIs)
The most common backend pattern: API Gateway validates Cognito tokens automatically.
Mobile/Web App --> sends Access Token in header --> API Gateway
|
v
Cognito Authorizer
(validates token)
|
Valid? | Invalid?
| |
v v
Lambda function 401 Unauthorized
(your code)
Setting Up a Cognito Authorizer
- In API Gateway, go to Authorizers
- Click Create authorizer
- Type: Cognito
- User Pool: select your user pool
- Token source: Authorization header
- Attach the authorizer to your API routes
Now every API request must include a valid Cognito Access Token. No token or expired token = 401 Unauthorized. Your Lambda function code does not need to validate tokens — API Gateway handles it.
User Groups and Role-Based Access
Creating Groups
- In Cognito, go to your User Pool > Groups
- Create groups:
admin,data-engineers,viewers - Assign users to groups
Using Groups in Your App
The ID Token includes the user’s groups:
{
"cognito:groups": ["admin", "data-engineers"]
}
In your Lambda function:
def handler(event, context):
claims = event['requestContext']['authorizer']['claims']
groups = claims.get('cognito:groups', '').split(',')
if 'admin' in groups:
# Admin access
return {'statusCode': 200, 'body': 'Admin data'}
else:
return {'statusCode': 403, 'body': 'Access denied'}
Lambda Triggers (Custom Logic)
Cognito can trigger Lambda functions at different points in the auth flow:
| Trigger | When It Fires | Use Case |
|---|---|---|
| Pre sign-up | Before user is created | Validate email domain, block disposable emails |
| Post confirmation | After email verification | Send welcome email, create user profile in DynamoDB |
| Pre authentication | Before sign-in | Check if account is locked, log sign-in attempts |
| Post authentication | After successful sign-in | Update last login timestamp, track device |
| Pre token generation | Before tokens are issued | Add custom claims to tokens (role, plan, org) |
| Custom message | When sending verification/MFA | Customize email/SMS templates |
Example: Add Custom Claims to Token
# Pre token generation Lambda
def handler(event, context):
# Add user's plan type to the token
event['response']['claimsOverrideDetails'] = {
'claimsToAddOrOverride': {
'plan': 'pro',
'org_id': 'org_12345'
}
}
return event
Now the Access Token includes plan: "pro" and org_id: "org_12345" that your API can use for authorization decisions.
Cognito vs Other Auth Providers
| Feature | AWS Cognito | Auth0 | Firebase Auth | Supabase Auth |
|---|---|---|---|---|
| Managed by | AWS | Okta | Supabase | |
| Free tier | 50,000 MAU | 7,500 MAU | Unlimited (basic) | 50,000 MAU |
| Social login | Google, Apple, Facebook, SAML | 30+ providers | Google, Apple, GitHub, etc. | Google, Apple, GitHub, etc. |
| MFA | SMS, TOTP | SMS, TOTP, Push | SMS, TOTP | TOTP |
| API Gateway integration | Native (AWS) | Via JWT validation | Via JWT validation | Via JWT validation |
| Lambda triggers | Native | Actions/Rules | Cloud Functions | Edge Functions |
| Best for | AWS-native apps | Enterprise SSO | Firebase ecosystem | Supabase ecosystem |
| Pricing | Per MAU after 50K | Per MAU after 7.5K | Free (basic) | Per MAU after 50K |
Choose Cognito when you are building on AWS and want native integration with API Gateway, Lambda, S3, and DynamoDB.
Pricing
| Component | Free Tier | After Free Tier |
|---|---|---|
| User Pool (direct sign-in) | 50,000 MAU free | $0.0055 per MAU |
| User Pool (federated/social) | 50 MAU free | $0.015 per MAU |
| Advanced security | Not free | $0.050 per MAU |
| SMS for MFA | N/A | $0.01-0.05 per message |
MAU = Monthly Active User (a user who signs in at least once in a month).
Example: 10,000 users signing in with email/password = free. 10,000 users signing in with Google = $150/month (10,000 x $0.015).
Common Mistakes
-
Generating a client secret for public apps — web and mobile apps are public clients. Never generate a client secret for them. Client secrets are for server-to-server (confidential) apps only.
-
Storing tokens in localStorage — vulnerable to XSS attacks. Use httpOnly cookies or secure in-memory storage. Amplify handles this correctly by default.
-
Not handling token refresh — Access tokens expire in 1 hour. Your app must automatically refresh them using the Refresh Token. Amplify does this automatically.
-
Validating tokens client-side only — always validate tokens server-side (API Gateway or Lambda). Client-side validation can be bypassed.
-
Not configuring account recovery — if users forget their password and you have no recovery flow, they are locked out permanently. Always enable email or phone recovery.
-
Using Cognito default email for production — limited to 50 emails/day. Switch to Amazon SES for production apps.
Interview Questions
Q: What is AWS Cognito? A: A managed authentication and authorization service. It handles user sign-up, sign-in, token management, MFA, social login, and password policies. It has User Pools (user directory and auth) and Identity Pools (AWS credentials for authenticated users).
Q: What is the difference between User Pools and Identity Pools? A: User Pools handle authentication — who the user is (sign-up, sign-in, tokens). Identity Pools handle authorization to AWS services — giving authenticated users temporary AWS credentials to access S3, DynamoDB, etc. directly.
Q: What are the three tokens Cognito issues? A: ID Token (user identity info — name, email, groups), Access Token (authorization — sent to APIs in the Bearer header), and Refresh Token (long-lived token to get new ID and Access tokens without re-signing in).
Q: How does Cognito integrate with API Gateway? A: Create a Cognito Authorizer in API Gateway that validates the Access Token from the request header. Invalid or expired tokens get a 401 response. Valid tokens pass through to the Lambda function with the user claims available in the event context.
Q: How do you add custom logic to the auth flow? A: Use Lambda Triggers. Cognito triggers Lambda functions at various points — pre sign-up (validate), post confirmation (welcome email), pre token generation (add custom claims), and more. This lets you customize auth behavior without modifying Cognito itself.
Wrapping Up
AWS Cognito is the security system for your applications. It handles the complex, security-critical parts of authentication so you can focus on building features.
The pattern is simple: User Pool for authentication, API Gateway for authorization, and Lambda Triggers for customization. Whether you are building a web app, mobile app, or API backend, Cognito provides the security layer that every production application needs.
And just like a professional security system, it is better to use a proven, managed solution than to build your own. The stakes are too high for DIY authentication.
Related posts: – AWS Amplify Explained – Building a REST API with FastAPI on AWS Lambda – AWS S3 for Data Engineers – Python for Data Engineers
Naveen Vuppula is a Senior Data Engineering Consultant and app developer based in Ontario, Canada. He writes about Python, SQL, AWS, Azure, and everything data engineering at DriveDataScience.com.