Amazon Cognito sits on the public internet and issues both application tokens and real AWS credentials, so a writable attribute, a generous guest role or a token that is never revoked can give anonymous users access to your AWS account. This guide covers the two halves of Cognito: user pools, which authenticate customers and issue JWTs, and identity pools, which exchange those tokens (or nothing at all, for guests) for temporary AWS credentials. It sets out the configuration choices that matter for security, how to verify and revoke tokens, how to log and detect abuse, and the misconfigurations that recur in assessments. It is for application security engineers, cloud architects and teams building customer sign-in on AWS. For customer identity strategy in general, see the Customer IAM (CIAM) Guide; feature behaviour here was checked against the Amazon Cognito Developer Guide on 27 October 2026.
Key takeaways
- Identity pools hand out AWS credentials: an unauthenticated role is AWS access for anyone who knows the identity pool ID, which is usually embedded in the client app.
- Trust policies must check
audandamr: IAM now requires the identity pool ID condition, but older roles and missingamrchecks remain common. - App clients can write every attribute by default: any attribute used for authorisation must be removed from
WriteAttributeson every app client. - Verify tokens properly: check signature,
iss,token_use,audorclient_idandexp, and remember that offline verification cannot see revocation. - Turn on the defences that are off by default: refresh token rotation, threat protection in audit mode first, identity pool data event logging and user existence error suppression on API-created clients.
How identity and access work in Amazon Cognito
| Component | What it does | What it issues | Main security decision |
|---|---|---|---|
| User pool | User directory and OIDC provider: sign-up, sign-in, MFA, federation to social, SAML and OIDC IdPs, managed login pages | ID token, access token, refresh token | App client settings, attribute permissions, token lifetimes, threat protection |
| App client | An application's configuration within the user pool, public or with a client secret | Tokens for that client | Allowed flows, read and write attributes, revocation, rotation |
| Resource server | Defines custom OAuth scopes for your APIs | Scopes in access tokens | Scope design for APIs and machine-to-machine clients |
| Identity pool | Exchanges a user pool or other IdP token, or no token for guests, for AWS credentials | Temporary AWS credentials via AssumeRoleWithWebIdentity | Guest access, role selection rules, IAM role permissions, basic or enhanced flow |
Tokens
The ID token carries user attributes and has an aud equal to the app client ID. The access token carries scopes, cognito:groups and client_id. The refresh token is encrypted and opaque. ID and access tokens default to one hour and can be set between 5 minutes and 1 day; refresh tokens default to 30 days and can be set from 60 minutes to 10 years. Tokens can contain personal data and details of your authorisation model, so protect them in transit and at rest. For general token hygiene see the Token and Session Security Guide.
Verifying user pool JWTs
- Confirm the token is a three-part JWT and that
algisRS256. - Match
kidagainst the keys athttps://cognito-idp.<Region>.amazonaws.com/<userPoolId>/.well-known/jwks.json, cached bykidand refreshed when an unknownkidarrives with the correct issuer. - Check
explocally. - Check
aud(ID token) orclient_id(access token) equals your app client ID. - Check
issequalshttps://cognito-idp.<Region>.amazonaws.com/<userPoolId>. - Check
token_useisaccessfor APIs that accept access tokens only, oridwhere you deliberately accept ID tokens.
AWS recommends the aws-jwt-verify library for Node.js, or any reputable OpenID Foundation listed library elsewhere. APIs should authorise on access tokens and scopes rather than ID tokens. See the JWT Security Guide.
Identity pools: authenticated and guest identities
Every identity pool identity is authenticated or unauthenticated, and each type maps to an IAM role. Guest access gives users who never signed in a unique identity ID and AWS credentials. The identity pool ID needed to request them ships inside the web or mobile app, so treat the unauthenticated role as public. The trust policy for both roles uses "Federated": "cognito-identity.amazonaws.com" and sts:AssumeRoleWithWebIdentity, with conditions on cognito-identity.amazonaws.com:aud (the identity pool ID) and cognito-identity.amazonaws.com:amr (authenticated or unauthenticated). For how these sessions behave, see the AWS STS and AssumeRole Guide.
| Flow | How credentials are obtained | Guardrails | Use when |
|---|---|---|---|
| Enhanced (simplified) flow | Cognito selects the role and calls STS on the app's behalf | Guest sessions get a scope-down inline session policy plus the managed policy AmazonCognitoUnAuthedIdentitiesSessionPolicy, limiting services and actions | Default choice |
| Basic (classic) flow | The app calls AssumeRoleWithWebIdentity itself and can name any role | No automatic scope-down; app can bypass role selection rules | Only when a required service is outside the enhanced flow list |
Do not use aws:SourceIp conditions in roles assumed through the enhanced flow, because Cognito makes the STS request, so the source IP never matches the user.
Admin roles and privileged access
Cognito administration is privileged access to your customers' accounts. The administrative APIs can create users, set passwords, mark email addresses as verified and sign users out.
- Separate administration from the app: the application's runtime role should not hold
cognito-idp:Admin*actions unless it genuinely needs them, and nevercognito-idp:AdminSetUserPassword,AdminUpdateUserAttributesorUpdateUserPoolClienton the production pool from a public-facing service. - Treat
email_verifiedas sensitive: an administrator can set it to true withAdminUpdateUserAttributes. Verified email and phone aliases transfer between accounts: if a user verifies an address that is already a verified alias on another account, Cognito moves the alias and marks it unverified on the original account. Test account recovery and linking flows against this behaviour. - Protect pool configuration: changes to app client flows, callback URLs, identity providers, Lambda triggers and identity pool roles should go through infrastructure as code with review. A changed callback URL or added IdP is an account takeover path.
- Guard Lambda triggers: pre sign-up, pre token generation and migration triggers run with their own roles and can alter claims. Whoever can edit trigger code controls the tokens.
- Scope the identity pool roles: the authenticated role is effectively granted to every customer. Use
${cognito-identity.amazonaws.com:sub}policy variables or principal tags so each user can only reach their own S3 prefix or DynamoDB items.
Integrations, API tokens and service accounts
Attribute permissions
A new app client can read and write all standard and custom attributes. If WriteAttributes is not set, users can change any attribute for themselves with UpdateUserAttributes. Because attributes are shared across every app client in the pool, a value written through one client appears in tokens issued by all of them. AWS's guidance is direct: if your application or identity pool makes authorisation decisions on an attribute (for example custom:role or custom:tenant_id), remove it from the WriteAttributes of every app client. Custom attributes cannot be deleted or changed after creation, so plan the schema before production. The legacy dev: developer attributes have been replaced by app client permissions.
Role selection and principal tags
Identity pools can choose a role per provider with up to 25 rules on token claims, or honour a preferred_role from user pool group membership. If no rule matches, role resolution either denies credentials or falls back to the authenticated role; choose deny. Attributes for access control map claims to principal tags (by default sub and aud) that IAM policies can test. Rules and tags are only as trustworthy as the claims behind them, which is why attribute write permissions matter.
Machine-to-machine clients
App clients with a client secret can use the OAuth client credentials grant against custom scopes defined on a resource server. These are non-human identities: store the client secret in a secrets manager, give each calling service its own app client, keep scopes narrow and rotate the secret on a schedule. Threat protection does not apply to client credentials requests, so monitor them separately. See the OAuth 2.0 Security Best Current Practice Guide.
Federation to external IdPs
User pools can federate to SAML and OIDC providers. Map IdP attributes carefully: a mapping into an attribute used for authorisation hands that decision to the IdP's administrators. Threat protection cannot be used with federated sign-in, so rely on the IdP's own controls. See the Customer IAM (CIAM) Guide.
Logging and detection
| Source | What it records | What to watch |
|---|---|---|
CloudTrail management events, cognito-idp.amazonaws.com | User pool API calls (AwsApiCall) and managed login or hosted UI requests (AwsServiceEvent, for example Login_GET, Token_POST, signup_POST); the user's sub, not username | Spikes of NotAuthorizedException by source IP, bursts of ForgotPassword, admin calls from unexpected principals, client and IdP configuration changes |
| CloudTrail data events for identity pools | GetId, GetCredentialsForIdentity, GetOpenIdToken and others; not logged by default and charged separately | Guest identity creation rates, credentials issued to unauthenticated identities, use from unusual networks |
| CloudTrail for the identity pool roles | What guest and authenticated credentials actually do | Calls outside the expected API set; enumeration such as ListBuckets or GetCallerIdentity |
| Threat protection logs (Plus plan) | Authentication details, risk assessments and session metadata, exportable to S3, CloudWatch Logs or Amazon Data Firehose | High-risk sign-ins, compromised credential detections, blocked IPs |
Cognito masks passwords and tokens in CloudTrail as HIDDEN_DUE_TO_SECURITY_REASONS but does not mask personal data placed in other request fields. Relevant ATT&CK techniques are T1110.004 Brute Force: Credential Stuffing, T1078.004 Valid Accounts: Cloud Accounts for misuse of issued credentials, and T1580 Cloud Infrastructure Discovery for guests probing the account.
Metrics
- Guest role permissions: number of actions allowed to the unauthenticated role; target zero if guests are not needed.
- Authorisation attributes writable by any app client: target zero.
- App clients with refresh token rotation and revocation enabled: target 100 percent.
- Credential stuffing signal: failed sign-ins per hour and per source IP against a baseline.
- Threat protection coverage: share of password-based sign-ins assessed in full function mode.
Hardening baseline
| Setting | Default | Baseline |
|---|---|---|
| Guest access on identity pools | Off until activated | Off unless a guest use case is documented; if on, near-zero permissions and per-identity resource scoping |
| Basic (classic) flow | Off | Off |
| Role trust conditions | aud enforced for new and edited policies | aud plus amr on every role; edit legacy roles to add them |
| Role resolution when no rule matches | Configurable | Deny |
App client WriteAttributes | All attributes | Explicit minimal list excluding authorisation attributes |
PreventUserExistenceErrors | Enabled in console, LEGACY via API | ENABLED on every client |
| Token revocation | Enabled on new clients | Enabled on all clients, including older ones |
| Refresh token rotation | Off | Enabled with a short RetryGracePeriodSeconds |
| Token lifetimes | 1 hour ID and access, 30 days refresh | Shortest access token your offline verifiers can tolerate; refresh lifetime matched to risk |
| MFA | Configurable | Required or adaptive; prefer passkeys or authenticator apps over SMS |
| Threat protection | Requires Plus plan | Audit only for two weeks or more, then full function |
| Rate limiting | Not provided by threat protection | AWS WAF web ACL on the user pool |
Rollout
- Inventory user pools, app clients, identity pools and their roles; export each client's attribute permissions, flows and token settings.
- Close public AWS access first: review unauthenticated roles, switch any basic flow pools to enhanced flow where possible, add
amrconditions, and set role resolution to deny. - Lock attributes: set explicit
WriteAttributeson every client in a test pool, run the app's sign-up and profile flows, then promote. - Tokens: enable revocation on older clients, then rotation; move integrations from
REFRESH_TOKEN_AUTHtoGetTokensFromRefreshToken, which rotation requires. - Threat protection: enable audit only, review risk decisions for at least two weeks, then switch to full function per app client. Rollback is returning the client to audit only.
- Logging: enable identity pool data events on the organisation trail and build the failed sign-in and
ForgotPasswordqueries into alerts.
Small versus large deployments: a single app can run one user pool with a few clients and no identity pool. Multi-tenant platforms should decide early whether tenants share a pool (tenant attribute, read-only, enforced in every API) or get separate pools, because attributes are shared across all clients in a pool and custom attributes cannot be changed later.
Common misconfigurations
- Guest roles with real permissions: an unauthenticated role allowed to read a bucket or invoke a function is open to anyone with the pool ID from the app bundle. In basic flow there is not even a scope-down policy.
- Self-writable authorisation attributes: users call
UpdateUserAttributesto setcustom:roleto admin, and the next ID token carries it to every API that trusts it. - Trusting ID tokens or skipping
token_use: an ID token minted for one app client is accepted as an API access token by another. - Assuming sign-out kills tokens everywhere: revoked tokens still pass offline JWT checks until
exp, and managed login cookies surviveGlobalSignOutunless users are sent to the Logout endpoint. - Username enumeration through API-created clients left on
LEGACY, feeding credential stuffing of the kind that reached about 18,000 accounts and data on roughly 7 million people in the 23andMe breach. - Relying on threat protection for volume attacks: it applies no rate limits; put AWS WAF in front of the user pool.
Framework mapping
| Framework | Reference | Cognito control |
|---|---|---|
| NIST CSF 2.0 | PR.AA-01, PR.AA-03, PR.AA-05 | Customer and guest identity management, MFA and threat protection, least privilege identity pool roles |
| NIST SP 800-53 Rev. 5 | IA-2, IA-5, AC-6, AC-3, AU-2 | Authentication, token and secret management, scoped roles, attribute-based enforcement, CloudTrail events |
| OWASP ASVS 5.0 | V9 Self-contained Tokens, V10 OAuth and OIDC | JWT validation and OAuth client configuration |
| CIS Controls v8.1 | 6 Access Control Management, 8 Audit Log Management, 16 Application Software Security | MFA and access policy, Cognito logging, secure app integration |
| ISO/IEC 27001:2022 Annex A | 5.17, 8.5, 8.15 | Authentication information, secure authentication, logging |
| MITRE ATT&CK v20 | T1110.004, T1078.004, T1580 | Credential stuffing, misuse of issued AWS credentials, guest discovery |
Practitioner checklist
- Disable guest access unless documented; scope any unauthenticated role to the minimum.
- Confirm every identity pool role trust policy checks
audandamr. - Keep identity pools on the enhanced flow and set role resolution to deny.
- Set explicit
WriteAttributeson every app client and exclude authorisation attributes. - Verify JWTs fully, including
token_useandclient_id, and authorise APIs on access tokens. - Enable token revocation and refresh token rotation on every client.
- Set
PreventUserExistenceErrorstoENABLEDon every client. - Run threat protection in audit only, then full function, and add AWS WAF rate limits.
- Log identity pool data events and alert on failed sign-in and password reset bursts.
Standards and references
- AWS: Amazon Cognito identity pools IAM role trust and permissions
- AWS: Working with user attributes
- AWS: Verifying JSON web tokens
- AWS: Ending user sessions with token revocation
- AWS: Refresh tokens
- AWS: Advanced security with threat protection
- AWS: Logging Amazon Cognito API calls with AWS CloudTrail
- OWASP: Application Security Verification Standard 5.0
Related NHI Mgmt Group resources: Customer IAM (CIAM) Guide · AWS STS and AssumeRole Guide · Token and Session Security Guide · Account Takeover Prevention Guide · AWS Security Guide