What Is Cognito?
Cognito is AWS's managed authentication service. It handles user registration, login, password reset, MFA, social sign-in (Google, Apple, Facebook), and SAML/OIDC federation. You get a user directory and JWT token issuance without building auth from scratch.
It competes with Auth0, Firebase Auth, and Azure AD B2C.
When to Use Cognito
Good fit:
- You're all-in on AWS and want auth that integrates natively
- You need basic auth (sign up, sign in, MFA, password reset)
- Your budget is limited (Cognito is cheap at scale)
- You want API Gateway JWT authorizer integration (zero-code auth at the API layer)
Consider alternatives (Auth0, Clerk, etc.) when:
- You need a polished, customizable login UI out of the box
- You need advanced features (breached password detection, bot detection, adaptive MFA)
- Developer experience is a priority (Cognito's docs and SDK are rough)
- You need strong multi-tenancy with per-tenant branding
The honest take: Cognito works and it's cheap. The developer experience used to be frustrating. The old hosted UI was ugly and the error messages are cryptic. The new Managed Login (launched late 2024) significantly improves this with a no-code visual branding editor for the full user journey (sign-up, login, password recovery, MFA). It's not Auth0-level polish, but it's no longer embarrassing.
Feature Plans
Cognito now has three pricing tiers:
| Lite | Essentials | Plus | |
|---|---|---|---|
| Price | $0.0055/MAU | $0.015/MAU | $0.02/MAU |
| Free tier | 10,000 MAU | 10,000 MAU | None |
| Managed Login (branded UI) | No | Yes | Yes |
| Passwordless (passkeys, email OTP) | No | Yes | Yes |
| Advanced threat protection | No | No | Yes |
| Compromised credential detection | No | No | Yes |
| Multi-region replication | No | Yes | Yes |
| Best for | Basic auth, budget-constrained | Most production apps | High-security, regulated |
Essentials is the default for new user pools and covers what most applications need. Lite is roughly the old pricing model. Plus adds the security features that were previously the expensive "Advanced Security Features" add-on. Now bundled and cheaper.
Multi-Region Replication
Launched June 2026. Cognito can now synchronize user data, credentials, and pool configurations to a secondary region in near real-time:
- One-directional replication (primary β secondary)
- Users can authenticate against the secondary region during a failover
- No forced password resets when failing over
- Available on Essentials and Plus plans (not Lite)
This solves Cognito's biggest enterprise complaint: it was single-region, meaning a regional outage took out authentication entirely. With MRR, you designate a standby region and can fail over without users noticing.
Limitation during failover: New user registrations are disabled in the secondary region. The standby is for authentication continuity, not full read-write operation.
Core Concepts
User Pool
The user directory. Stores usernames, passwords, attributes (email, phone, custom attributes like tenant_id). Issues JWT tokens.
App Client
Your application's registration with the user pool. Defines which auth flows are allowed, token validity periods, and OAuth scopes.
Identity Pool (Cognito Identity)
Separate from User Pools. Exchanges tokens (from User Pools, social providers, or SAML) for temporary AWS credentials. Use when your client needs to call AWS services directly (S3 upload from browser, IoT device registration).
Tokens
Cognito issues three tokens:
- ID Token: User identity claims (email, name, custom attributes). Use for your application logic.
- Access Token: Scopes and groups. Use for API authorization.
- Refresh Token: Long-lived (default 30 days). Exchange for new ID/access tokens without re-authentication.
API Gateway Integration
The cheapest, fastest way to protect an API:
HTTP API + JWT Authorizer
API Gateway validates the token before invoking your backend. No Lambda, no code:
- Validates JWT signature against Cognito's JWKS
- Checks token expiration
- Verifies issuer
- Passes claims through to the backend in the request context
Invalid tokens get a 401 before your Lambda is even invoked (and you don't pay for the invocation).
REST API + Cognito Authorizer
Similar concept but using the REST API's built-in Cognito integration. Validates tokens and provides user pool claims to the backend.
Custom Attributes
Store application-specific data on the user:
custom:tenant_id β "acme-corp"
custom:role β "admin"
custom:plan β "enterprise"
These appear in the ID token. Useful for multi-tenant applications where you need tenant context on every request without a database lookup.
Limitation: Custom attributes can't be searched or filtered. You can't query "all users in tenant X" from Cognito directly. If you need that, maintain a separate user table in DynamoDB.
Lambda Triggers
Cognito invokes Lambda functions at specific points in the auth flow:
| Trigger | Use case |
|---|---|
| Pre Sign-up | Validate email domain, block disposable emails |
| Post Confirmation | Create user record in DynamoDB, send welcome email |
| Pre Token Generation | Add custom claims to tokens based on database lookup |
| Custom Message | Customize verification emails |
| Pre Authentication | Check if user is suspended, rate-limit login attempts |
Pre Token Generation is the most powerful. Inject dynamic claims (permissions, tenant info) into the token at issuance time.
Managed Login vs Custom UI
Managed Login (recommended starting point)
The new default. AWS hosts the login pages with a visual branding editor. Customize colors, logo, fonts, and layout without code. Covers sign-up, sign-in, password recovery, MFA, and social login screens. Available on Essentials and Plus plans.
Good for:
- Most applications (it's genuinely decent-looking now)
- Getting to production fast without building auth UI
- Teams without frontend resources dedicated to auth screens
Custom UI
Build your own login page entirely. Use Cognito's APIs (InitiateAuth, RespondToAuthChallenge) or the Amplify Auth library. Full control, more work. Use when you need a deeply branded experience or flows that Managed Login doesn't support.
Pricing
Cognito's pricing depends on your feature plan:
- Lite: First 10,000 MAU free, then $0.0055/user (volume discounts at scale)
- Essentials: First 10,000 MAU free, then $0.015/user. Includes managed login, passwordless, MRR
- Plus: $0.02/user (no free tier). Includes threat protection, compromised credential detection
At 100K users on Essentials: ~$1,350/month. Auth0 at the same scale: $2,000+/month. The cost advantage remains, especially at scale.
Common Gotchas
- Access tokens don't have an
audclaim. Only ID tokens do. This trips up JWT validation libraries that expect audience. - Custom attributes are immutable by default. Once set, only admins can change them unless you mark them as mutable.
- User pool configuration is hard to change after creation. Some settings (required attributes, username format) are permanent. Plan carefully before creating a production pool.
- Cognito has strict rate limits on admin APIs (40 TPS default for operations like AdminCreateUser). Bulk imports need special handling.
- Token revocation is limited. You can revoke refresh tokens, but access/ID tokens are valid until expiry. Keep token lifetime short (1 hour).
CDK Example
import { UserPool, UserPoolClient, AccountRecovery, Mfa } from 'aws-cdk-lib/aws-cognito';
const userPool = new UserPool(this, 'Users', {
userPoolName: 'my-app-users',
selfSignUpEnabled: true,
signInAliases: { email: true },
autoVerify: { email: true },
mfa: Mfa.OPTIONAL,
passwordPolicy: {
minLength: 12,
requireLowercase: true,
requireUppercase: true,
requireDigits: true,
requireSymbols: false,
},
accountRecovery: AccountRecovery.EMAIL_ONLY,
customAttributes: {
tenant_id: new StringAttribute({ mutable: false }),
},
removalPolicy: RemovalPolicy.RETAIN,
});
const client = userPool.addClient('WebApp', {
authFlows: { userSrp: true },
oAuth: {
flows: { authorizationCodeGrant: true },
scopes: [OAuthScope.OPENID, OAuthScope.EMAIL, OAuthScope.PROFILE],
callbackUrls: ['https://myapp.com/callback'],
logoutUrls: ['https://myapp.com'],
},
accessTokenValidity: Duration.hours(1),
idTokenValidity: Duration.hours(1),
refreshTokenValidity: Duration.days(30),
});
Further Reading
- Cognito Developer Guide
- Cognito pricing
- JWT token verification
- Lambda triggers
- Using Cognito with .NET: JWT validation in ASP.NET Core, admin API usage, and multi-tenant patterns
Related Blog Posts
Looking for hands-on help? View my AWS architecture services β