Service spotlight: Amazon Cognito user pools vs identity pools
Half the confusion I’ve seen around Cognito isn’t about how it works — it’s that “Cognito” is the marketing name for two separate services that happen to share a console tab. Get the two confused and you either build an auth flow that can’t touch AWS resources, or wire up AWS credentials for users who were never actually authenticated.
What it actually is
User pools are the authentication half: a managed user directory that handles sign-up, sign-in, password policies, MFA, and email/SMS verification, and issues JWTs (ID, access, and refresh tokens) on successful login. They can front their own hosted UI or federate to social IdPs and SAML/OIDC providers, so “login with Google” and “login with your corporate Okta” both terminate in the same user pool.
Identity pools (Cognito Federated Identities) are the authorization half: given a token — from a Cognito user pool, a social IdP, SAML, or even an unauthenticated “guest” request — an identity pool exchanges it for temporary AWS credentials via STS, scoped by an IAM role. That’s the piece that lets a mobile app upload directly to S3 or call DynamoDB without a backend in the middle, using credentials that expire instead of a long-lived API key baked into the app.
The two compose but aren’t interchangeable: a user pool alone gives you “who is this person,” not “what can they touch in AWS.” An identity pool alone will happily hand out credentials to unauthenticated guests if you let it — it doesn’t do authentication itself, it just brokers whatever token you hand it.
Where it earns its keep
- You skip building and hardening your own auth service. Password hashing, MFA enrollment, account recovery, and JWT issuance are the kind of thing that’s deceptively easy to get 90% right and dangerously easy to get the last 10% wrong (timing attacks on password comparison, token replay, session fixation). Cognito’s user pools cover that surface area so it’s not your team’s to maintain.
- Direct-to-AWS access without a backend proxy. A static site or
mobile app can let an authenticated user write straight to an S3 prefix
scoped to their identity (
${cognito-identity.amazonaws.com:sub}in the IAM policy) instead of routing every upload through an API Gateway + Lambda pair whose only job is forwarding bytes. - Federation is handled once, centrally. Add a SAML IdP or a social login provider to the user pool and every app using it gets that login option — you’re not reimplementing OAuth handshakes per client.
Where it goes wrong in practice
The tier structure is the sharpest edge. Cognito’s current pricing splits user pools into Lite, Essentials, and Plus feature plans, and features that look like they should be table stakes — SAML/OIDC federation, advanced security features like compromised-credential and risk-based adaptive authentication — only exist on Essentials or Plus, billed per monthly active user (MAU). A team that prototypes on Lite because the free allowance looks generous, then adds “sign in with our IdP” for an enterprise customer, discovers that single feature moves the entire pool’s MAU count onto the paid tier, not just the new users using it. Check which tier a feature needs before you promise it in a sprint.
The other recurring mistake is treating identity pool credentials as a
substitute for real authorization. STS credentials scoped to an
identity-pool IAM role are still full IAM credentials — if the attached
role is too broad, an authenticated (or worse, guest-enabled)
unauthenticated identity can reach far more than “upload your own
profile picture.” Audit identity pool roles the same way you’d audit any
IAM role handed to untrusted clients, with Condition blocks scoping
access to the caller’s own identity ID, not just a wide S3 prefix.
A practical tip
Before adding a Cognito feature to a design doc, check the feature plan
comparison for the tier it
actually requires — “advanced security” and third-party federation are
the two that most often get assumed as free defaults and aren’t. And if
you’re issuing AWS credentials via an identity pool, run aws sts
get-caller-identity with a test unauthenticated identity’s credentials
before shipping, to confirm guest access is scoped as tightly as you
think it is rather than as tightly as you meant it to be.
Join the discussion
Comments for this post live on social — reply to the thread.
Related posts
Cloud roundup: macOS Screen Sharing bug now under attack
A patched macOS Screen Sharing flaw is being exploited to plant crypto miners, a Windows Defender bypass has no fix yet, and EC2 gets built-in app health checks.
Cutting NAT gateway costs with VPC endpoints that actually help
How gateway and interface VPC endpoints replace NAT gateway traffic for AWS API calls, what they cost instead, and which traffic still has to go through NAT.
Cloud roundup: S3 finally names the policy that denied you
AWS S3 access-denied errors now name the exact policy ARN, Client VPN gets a scriptable CLI, and OpenAI ships authorized offensive-security models on Bedrock.