Cognito's User Pool vs Identity Pool Split
Amazon Cognito is one brand name covering two distinct services, and mixing them up is the single most common source of confusion for anyone new to it.
Search across all documentation pages
Amazon Cognito is one brand name covering two distinct services, and mixing them up is the single most common source of confusion for anyone new to it.
User Pools answer "who are you." Identity Pools answer "what can you call in AWS." Understanding that split before writing any code will save you from a lot of misdirected debugging later.
This page builds the mental model both services share, and where each one starts and stops.
A user pool is a managed user directory. It stores usernames, password hashes, and user attributes, and it runs the sign-up, sign-in, and account-recovery flows.
When a user signs in successfully, the user pool returns three JWTs: an ID token, an access token, and a refresh token. These prove who the user is to your own backend or API.
An identity pool is a separate, optional service. It does not store users. Its only job is to exchange a trusted identity - most commonly a user pool JWT - for short-lived AWS credentials scoped by an IAM role.
In boto3, these map to two different service clients: cognito-idp (Identity Provider) for user pools, and cognito-identity for identity pools. In the AWS SDK for JavaScript v3, they are two separate npm packages: @aws-sdk/client-cognito-identity-provider and @aws-sdk/client-cognito-identity.
A user pool can function completely on its own. An identity pool is useless without a trusted identity source feeding it, whether that is a user pool, a social provider, or SAML/OIDC.
The two services connect through one specific step: linking.
When you create an identity pool, you configure it with one or more authenticated providers - typically your user pool's ID and app client ID. This tells the identity pool "trust JWTs signed by this user pool."
The runtime flow looks like this. First, a user signs in against the user pool via InitiateAuth, receiving an ID token. Second, the client calls the identity pool's GetId operation, passing that ID token under the user pool's provider name. Third, the client calls GetCredentialsForIdentity, again passing the token, and receives an AccessKeyId, SecretKey, and SessionToken.
# --- Python (boto3) ---
import boto3
identity_client = boto3.client("cognito-identity")
# Exchange a user pool ID token for temporary AWS credentials.
provider_name = "cognito-idp.us-east-1.amazonaws.com/us-east-1_ExamplePool"
identity = identity_client.get_id(
IdentityPoolId="us-east-1:1111-2222-example-pool",
Logins={provider_name: id_token},
)
creds = identity_client.get_credentials_for_identity(
IdentityId=identity["IdentityId"],
Logins={provider_name: id_token},
)["Credentials"]// --- TypeScript (AWS SDK v3) ---
import {
CognitoIdentityClient, GetIdCommand, GetCredentialsForIdentityCommand,
} from "@aws-sdk/client-cognito-identity";
const identityClient = new CognitoIdentityClient({});
const providerName = "cognito-idp.us-east-1.amazonaws.com/us-east-1_ExamplePool";
const { IdentityId } = await identityClient.send(new GetIdCommand({
IdentityPoolId: "us-east-1:1111-2222-example-pool",
Logins: { [providerName]: idToken },
}));
const { Credentials } = await identityClient.send(new GetCredentialsForIdentityCommand({
IdentityId,
Logins: { [providerName]: idToken },
}));The credentials returned are scoped by whichever IAM role the identity pool's role mapping assigns - either a single default role for all authenticated users, or a role chosen per-user based on a rule or a token claim.
A common architectural question is whether you need an identity pool at all.
| Scenario | Needs an identity pool? |
|---|---|
| Client calls your own backend API, backend calls AWS with its own role | No - the backend's role is enough |
| Client-side app (mobile, SPA) calls S3, DynamoDB, or other AWS services directly | Yes - it needs temporary AWS credentials |
| You only need to know who is logged in for app-level authorization | No - a validated JWT is enough |
| Guest access to limited AWS resources before sign-in | Yes - identity pools support unauthenticated identities |
Identity pools also support unauthenticated identities, letting a guest user receive limited-scope AWS credentials before ever signing in - useful for anonymous analytics uploads or public read access patterns.
Role mapping can be token-based, reading a custom claim from the JWT to pick a role, which is how you implement per-tenant or per-group AWS access without creating one identity pool per tenant.
Because the credentials from GetCredentialsForIdentity are genuine temporary AWS credentials issued via STS under the hood, they expire and must be refreshed the same way any assumed-role credentials do - your client SDK should request new ones before the old set lapses, not on an unhandled 403.
cognito-idp and cognito-identity, two separate clients with unrelated operations.User Pools authenticate (prove who a user is); Identity Pools authorize (exchange that proof for temporary AWS credentials).
No. Many apps only need a user pool because they authenticate against their own backend. An identity pool is only needed when a client must call AWS services directly.
Three JWTs: an ID token (identity claims), an access token (scopes/permissions for your own API), and a refresh token (used to get new tokens without re-authenticating).
Temporary AWS credentials - an access key ID, secret key, and session token - scoped by the IAM role the identity pool's role mapping assigns.
cognito-idp for user pools and cognito-identity for identity pools. They are unrelated clients with different operations.
Yes. An identity pool can trust social identity providers, SAML, or OIDC providers directly as its authenticated provider, with no user pool in the picture at all.
The rule an identity pool uses to decide which IAM role to hand out - either one default role for everyone, or a role selected per-user from a rule or token claim.
Yes. Identity pools support unauthenticated identities, issuing limited-scope temporary credentials to users who have not signed in, commonly used for public or anonymous access patterns.
Yes. They are genuine STS-issued temporary credentials and expire like any assumed-role credentials. Client SDKs should refresh them proactively before they lapse.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 25, 2026