Advanced Identity (Cognito, STS, cross-account roles) — Cheat Sheet (DVA-C02)
Verified against AWS documentation on 2026-10-12 · ⚠️ = changed vs the course or older material: learn the value shown here (full list in notes/advanced-identity-guide.md#changed-vs-older-material; rows you confirm also go to notes/current-facts.md) · explanations and examples: notes/advanced-identity-guide.md.
Cognito user pools vs identity pools
| Topic | Current facts | Memory hook |
|---|---|---|
| Cognito user pool | User directory + OIDC provider: signs users in (local, or federated Google, Facebook, Apple, Amazon, SAML, OIDC) and issues ID, access and refresh tokens | Pool of users → tokens |
| Cognito identity pool | Swaps a user pool ID token, social/OIDC/SAML token or nothing (guest) for temporary AWS credentials of an IAM role via STS | Pool of identities → AWS keys |
| User pool + identity pool together | Sign in at the user pool, pass the ID token in Logins (cognito-idp.<region>.amazonaws.com/<pool-id>), call AWS services directly |
Authenticate, then authorize |
| Guest (anonymous) access | Only identity pools have unauthenticated identities (AllowUnauthenticatedIdentities) |
Guests live in identity pools |
| Identity pool credential fields | AccessKeyId, SecretKey, SessionToken, Expiration; enhanced-flow credentials last 1 h |
|
| Cognito vs IAM users | App customers → Cognito; people and tools that run the AWS account → IAM / IAM Identity Center | |
| Cognito Sync | ⚠️ No longer open to new customers → AWS AppSync or DynamoDB | Sync has sunk |
User pool sign-up, sign-in and MFA
| Topic | Current facts | Memory hook |
|---|---|---|
| User pool app client | Per-app settings: auth flows, OAuth grants, token lifetimes, attribute read/write, optional client secret | |
| Client secret rules | Public (browser/mobile) clients have none; can't be added or removed after creation (new client); up to 2 secrets for rotation | Secrets live on servers |
SECRET_HASH |
Base64(HMAC-SHA256(key = client secret, msg = username + client ID)); missing → "Unable to verify secret hash for client" | |
| User account states | SignUp → UNCONFIRMED → CONFIRMED (code, AdminConfirmSignUp or pre sign-up trigger); admin-created → FORCE_CHANGE_PASSWORD; imported → RESET_REQUIRED |
|
| User pool auth flows | USER_SRP_AUTH (password never sent, best practice), USER_PASSWORD_AUTH, ADMIN_USER_PASSWORD_AUTH (IAM creds), CUSTOM_AUTH, REFRESH_TOKEN_AUTH, USER_AUTH (choice-based, Essentials+) |
SRP = Secret Remains Private |
Default ExplicitAuthFlows |
ALLOW_REFRESH_TOKEN_AUTH, ALLOW_USER_SRP_AUTH, ALLOW_CUSTOM_AUTH |
|
| User pools API authorization | Public (client ID): SignUp, InitiateAuth, ForgotPassword; token: GetUser, UpdateUserAttributes, GlobalSignOut; IAM: all Admin* and configuration calls |
|
| User pool MFA factors | SMS (SNS role), TOTP (AssociateSoftwareToken + VerifySoftwareToken), email OTP (Essentials/Plus + SES); passkeys and passwordless OTP are first factors (Essentials/Plus) |
|
| User pool MFA rules | Off / Optional / Required; federated users get MFA from their IdP; adaptive auth needs Optional; Required impossible with OTP passwordless | |
| Fixed at user pool creation | Sign-in identifiers (username vs email/phone vs aliases) and required attributes | |
| Custom attributes | Up to 50, custom: prefix, can't be removed or renamed, mutable or immutable |
|
sub attribute |
Immutable unique user ID → use it as your database key | The sub never changes |
PreventUserExistenceErrors |
ENABLED = generic errors; LEGACY (API default) = UserNotFoundException |
|
| User pool exceptions | UserNotConfirmedException, PasswordResetRequiredException, NotAuthorizedException, UsernameExistsException, CodeMismatchException, UserLambdaValidationException, TooManyRequestsException, FeatureUnavailableInTierException |
|
UpdateUserPool / UpdateUserPoolClient |
Omitted settings reset to defaults → send the full configuration | Update = replace |
| Blocking SDK sign-in | AWS WAF web ACL on the user pool; removing COGNITO from an app client only hides it in managed login |
User pool tokens and JWT validation
| Topic | Current facts | Memory hook |
|---|---|---|
| ID token | Identity claims (sub, attributes, cognito:groups); aud = app client ID; token_use = id |
ID = who |
| Access token | scope, client_id, username, groups; authorizes APIs and self-service calls; token_use = access |
Access = what |
| Refresh token | Opaque and encrypted; buys new ID and access tokens | |
| Cognito token lifetimes | ID/access default 1 h (5 min–1 day); refresh default 30 days (1 h–3,650 days) | |
| JWT validation steps | Signature (JWKS key by kid, RS256) → exp → iss → aud / client_id → token_use |
Sign, expiry, issuer, audience, use |
| Cognito JWKS URL | https://cognito-idp.<region>.amazonaws.com/<pool-id>/.well-known/jwks.json |
|
| JWT verification library | aws-jwt-verify: CognitoJwtVerifier.create({ userPoolId, tokenUse, clientId }) |
|
| Token refresh options | REFRESH_TOKEN_AUTH, GetTokensFromRefreshToken, token endpoint grant_type=refresh_token |
|
| Refresh token rotation | ⚠️ Optional per client; new refresh token each refresh; grace ≤ 60 s; needs GetTokensFromRefreshToken or token endpoint; same expiry window |
|
| Ending Cognito sessions | RevokeToken (refresh token), GlobalSignOut (own access token), AdminUserGlobalSignOut (IAM); offline validators still accept unexpired access tokens |
|
| Default scope from API sign-in | Access token carries only aws.cognito.signin.user.admin |
|
| API Gateway Cognito authorizer token | Accepts ID or access token; methods with authorization scopes need the access token | |
| Token for identity pools | The user pool ID token |
User pool Lambda triggers
| Topic | Current facts | Memory hook |
|---|---|---|
| Pre sign-up trigger | Allow-list or refuse new accounts; skip the code with autoConfirmUser, autoVerifyEmail, autoVerifyPhone; also fires for AdminCreateUser and a first federated sign-in |
Pre-approve |
| Post confirmation trigger | Runs once the account is confirmed (also after ConfirmForgotPassword): create the profile row, send a welcome |
|
| Pre / post authentication triggers | Pre: refuse a sign-in by throwing an error; post: audit a successful one; neither changes tokens | |
| Pre token generation trigger | Claims, groups, roles; V1_0 ID token; ⚠️ V2_0 adds access-token claims and scopes; V3_0 adds M2M; V2/V3 need Essentials or Plus |
Last stop before tokens |
| Migrate user trigger | User missing at password sign-in or ForgotPassword; finalUserStatus CONFIRMED keeps the password; never fires for SRP or passwordless |
Migration needs the password |
| Custom message trigger | smsMessage, emailMessage, emailSubject, must include the code placeholder |
|
| Custom auth challenge triggers | Define → Create → Verify auth challenge in CUSTOM_AUTH; not available in managed login |
|
| Custom email/SMS sender triggers | Third-party delivery; codes encrypted with your KMS key; configured by API/CLI only (KMSKeyID) |
|
| Trigger timeout | Synchronous, 5 s, not adjustable (custom senders excepted) | Five seconds or fail |
| Trigger invoke permission | Lambda resource policy for cognito-idp.amazonaws.com (aws:SourceArn = pool ARN); console adds it, CLI/IaC must add it |
|
| Trigger rejection error | API returns UserLambdaValidationException "<trigger> failed with error …" |
|
| Federated sign-in and triggers | No custom auth, migrate user, custom message or custom sender triggers |
Managed login, domains and OAuth
| Topic | Current facts | Memory hook |
|---|---|---|
| Managed login | ⚠️ Since 22 Nov 2024: branding editor, passkeys, localisation; Essentials/Plus; classic hosted UI in all plans and the only one in Lite; one branding version per domain | |
ManagedLoginVersion |
1 = classic hosted UI, 2 = managed login | |
| App clients created by API | Need CreateManagedLoginBranding before managed login pages work |
|
| Prefix domain format | <prefix>.auth.<region>.amazoncognito.com |
|
| Custom domain requirements | ACM certificate in us-east-1, parent-domain A record, alias to Cognito's CloudFront domain; ≤ 4 per Region | The certificate lives in Virginia |
| User pool OAuth endpoints | /oauth2/authorize, /oauth2/token, /oauth2/userInfo, /oauth2/revoke, /login, /logout, /oauth2/idpresponse, /saml2/idpresponse |
|
| Authorization code + PKCE | Most secure grant; tokens come from the token endpoint; refresh token included | Code + PKCE for public apps |
| Implicit grant | Tokens in the URL fragment, no refresh token, no PKCE → legacy and testing only | |
| Client credentials grant | M2M; client secret required; custom scopes only; access token only; billed separately; GetClientToken works without a domain |
Machines get access only |
| OAuth scopes in Cognito | openid → ID token; aws.cognito.signin.user.admin → self-service APIs; custom <resource-server>/<scope> |
|
| Managed login session cookie | Lasts 1 h; /logout clears it |
|
| Callback URL rules | HTTPS (http only for localhost), absolute, pre-registered, no fragment, ≤ 100 per app client | |
| Federated user sign-in | Only through /oauth2/authorize or managed login, never InitiateAuth |
Feature plans and threat protection
| Topic | Current facts | Memory hook |
|---|---|---|
| Lite plan | ⚠️ Basic sign-in, federation, classic hosted UI, SMS/TOTP MFA, ID-token customisation, triggers, M2M | |
| Essentials plan | ⚠️ Default for new pools: + managed login, passkeys, passwordless OTP, email MFA, choice-based sign-in, access-token customisation | |
| Plus plan | ⚠️ Essentials + threat protection (adaptive auth, compromised credentials, activity log export) | Plus protects |
| Threat protection modes | AdvancedSecurityMode AUDIT / ENFORCED requires tier PLUS; run audit-only first (≥ 2 weeks) |
|
| Compromised-credentials check | Sign-in, sign-up, password change; block or allow; password flows only (not SRP, not custom auth) | |
| Adaptive authentication | Risk low/medium/high → allow, optional MFA, require MFA, block (+ notify); user pool MFA must be Optional | |
| Threat protection gaps | Doesn't cover federated sign-in or M2M; no rate limiting → add AWS WAF | |
| Threat protection logs | Export to CloudWatch Logs, S3 or Data Firehose | |
| Feature not in plan | FeatureUnavailableInTierException |
ALB authentication
| Topic | Current facts | Memory hook |
|---|---|---|
| ALB authenticate actions | authenticate-cognito, authenticate-oidc; HTTPS listeners only |
|
| App client for ALB auth | Client secret + code grant + openid; callback https://<ALB DNS or CNAME>/oauth2/idpresponse in lowercase |
|
OnUnauthenticatedRequest |
authenticate (default, redirect), allow (no claims), deny (HTTP 401 when there is no session) |
|
| ALB authenticate defaults | SessionTimeout 604,800 s (7 days); cookie AWSELBAuthSessionCookie; scope openid |
|
x-amzn-oidc-data header |
User claims JWT signed with ES256; check signer = ALB ARN; key from public-keys.auth.elb.<region>.amazonaws.com/<kid> |
Data is signed |
| Legacy ALB headers | ⚠️ x-amzn-oidc-accesstoken and x-amzn-oidc-identity are unsigned → never authorize on them |
|
| ALB auth limits | Sign-in must finish in 15 min (else 401); claims + token > 11 KB → HTTP 500 | |
ALB jwt-validation action |
⚠️ Since 12 Nov 2025 for M2M bearer JWTs: RS256, iss + exp + ≤ 10 claims, JWKS ≤ 150 KB and ≤ 10 keys |
|
| SAML sign-in at an ALB | Federate the SAML IdP into a user pool, then authenticate-cognito |
Identity pools
| Topic | Current facts | Memory hook |
|---|---|---|
| Identity pool enhanced flow | GetId → GetCredentialsForIdentity; Cognito picks the role; credentials 1 h; role in the same account |
|
| Identity pool basic flow | GetId → GetOpenIdToken → AssumeRoleWithWebIdentity; client picks the role; keep off unless needed; no role mappings |
|
| Developer-authenticated identities | Backend calls GetOpenIdTokenForDeveloperIdentity with IAM credentials |
|
| Identity pool role trust policy | Federated: cognito-identity.amazonaws.com, sts:AssumeRoleWithWebIdentity, cognito-identity.amazonaws.com:aud (required) + :amr authenticated/unauthenticated |
aud = which pool, amr = who |
| STS API behind identity pools | ⚠️ AssumeRoleWithWebIdentity (the course writes "AssumeRoleForWebIdentity") |
|
| Guest scope-down policy | Enhanced-flow guests limited to a service list (S3, DynamoDB, Lambda, SQS, SNS, Kinesis, API Gateway, CloudWatch…); others → NotAuthorizedException |
|
| Role from token | User pool group role → cognito:preferred_role (lowest precedence number) / cognito:roles; optional CustomRoleArn |
|
| Role-mapping rules | Claim match → role; first match wins; ≤ 25 per provider; AmbiguousRoleResolution AuthenticatedRole or Deny |
|
| Attributes for access control | Token claims → session tags → ${aws:PrincipalTag/<key>}; trust policy also needs sts:TagSession |
|
| Identity pool per-user variable | ${cognito-identity.amazonaws.com:sub} = identity ID <region>:<guid> |
|
| Identity pool public APIs | GetId, GetCredentialsForIdentity need no AWS credentials |
STS and cross-account roles
| Topic | Current facts | Memory hook |
|---|---|---|
AssumeRole duration |
900 s up to the role's maximum; default 3,600 s | |
| Role maximum session duration | ⚠️ 1–12 h (aws iam update-role --max-session-duration); asking for more fails |
|
| Role chaining limit | Role-to-role sessions last at most 1 h, whatever the role's maximum; a chained request for more fails | A chain lasts one hour |
GetSessionToken |
IAM user; 15 min–36 h, default 12 h; root ≤ 1 h; used with MFA | |
GetFederationToken |
IAM user; 15 min–36 h, default 12 h; no session policy → no permissions | |
AssumeRoleWithWebIdentity guidance |
⚠️ Mobile apps → use Cognito; workloads with an OIDC IdP (e.g. CI/CD) → calling it directly is fine | |
AssumeRoot |
⚠️ Org management account or delegated admin; root task on a member account; ≤ 900 s; Regional endpoint only | |
GetCallerIdentity |
Needs no permission; works even under an explicit deny | |
| Cross-account assume requirement | Target role's trust policy + sts:AssumeRole allow in the caller's identity policy |
Both doors open |
| Same-account assume requirement | Identity-policy allow (trust trusts the account) OR trust policy naming the user | |
| External ID | sts:ExternalId trust condition for third parties; 2–1,224 chars; stops the confused deputy |
|
| Switching to a role | You give up your own permissions; resource-based policies let you keep them | |
| Session policies | 1 inline + ≤ 10 managed ARNs, ≤ 2,048 chars combined; result = intersection | |
| Session tags | ≤ 50; key 128 / value 256 chars; TransitiveTagKeys survive chaining; need sts:TagSession |
|
| Limits of role credentials | Can't call GetSessionToken or GetFederationToken |
|
| STS global endpoint | ⚠️ Served in the caller's Region for default-enabled Regions; opt-in Regions → us-east-1; prefer Regional endpoints | |
| STS request quota | 600 RPS per account per Region, shared by AssumeRole, GetCallerIdentity, GetSessionToken… |
STS with MFA
| Topic | Current facts | Memory hook |
|---|---|---|
| MFA condition keys | aws:MultiFactorAuthPresent (only in temporary-credential requests), aws:MultiFactorAuthAge (seconds since MFA) |
|
| Recommended MFA deny | Deny + BoolIfExists aws:MultiFactorAuthPresent false (also blocks long-term keys) |
If it doesn't exist, it isn't MFA |
| MFA allow form | Allow + Bool aws:MultiFactorAuthPresent true |
|
| MFA deny pitfall | Deny + Bool false lets long-term access-key requests through |
|
| STS MFA parameters | SerialNumber (device serial or arn:aws:iam::<acct>:mfa/<name>) + TokenCode (6 digits) |
|
GetSessionToken credential limits |
No IAM calls without MFA; STS only AssumeRole / GetCallerIdentity; no console sign-in |
|
| Role that requires MFA | Trust policy Bool aws:MultiFactorAuthPresent true; call assume-role --serial-number --token-code |
Policy evaluation
| Topic | Current facts | Memory hook |
|---|---|---|
| Evaluation order | Explicit deny → RCPs ⚠️ → SCPs → resource-based → identity-based → permissions boundary → session policy | Deny first, then every gate |
| Default decision | Implicit deny | |
| Explicit deny | Overrides any allow anywhere | |
| Cross-account evaluation | Trusted and trusting account evaluations must both allow | |
| Same-account resource-based policy | Naming a user or role session grants directly; naming a role ARN is still limited by boundary / session policy | |
| Policies that must explicitly allow | Role trust policies and KMS key policies | |
| SCP scope | Member accounts incl. their root user; not the management account; not service-linked roles; never grant | |
| Resource control policies | ⚠️ Since 13 Nov 2024: cap resource permissions in member accounts for any caller; launched for S3, STS, KMS, SQS, Secrets Manager, now dozens of services | |
| AccessDenied message hints | "with an explicit deny in a <type> policy" / "because no <type> policy allows the <action> action"; types include SCP, RCP, identity-based, resource-based, session, boundary, VPC endpoint, role trust | |
| Policy testing tools | aws iam simulate-principal-policy, IAM Access Analyzer validation, sts decode-authorization-message |
Policy variables
| Topic | Current facts | Memory hook |
|---|---|---|
| Policy language version for variables | "Version": "2012-10-17"; otherwise ${…} is literal text |
|
| Where variables work | Resource (after the fifth colon) and string/ARN conditions; never Action |
|
${aws:username} |
IAM users only; absent for roles, root and federated users | Usernames are for users |
${aws:userid} values |
Role session role-id:session-name; EC2 role role-id:instance-id; root = account ID |
|
${aws:PrincipalTag/<key>} |
Tags on users, roles or sessions → ABAC | |
| Identity pool policy variable | ${cognito-identity.amazonaws.com:sub} for per-identity S3 prefixes and dynamodb:LeadingKeys |
|
| Variable with no value | StringEquals doesn't match, StringNotEquals does; default syntax ${aws:PrincipalTag/team, 'company-wide'} |
|
| S3 home-folder policy | s3:ListBucket on the bucket with s3:prefix; object actions on bucket/home/${aws:username}/* |
Managed vs inline policies and PassRole
| Topic | Current facts | Memory hook |
|---|---|---|
| AWS managed policy | Created and updated by AWS; read-only; job functions such as AdministratorAccess, PowerUserAccess, ReadOnlyAccess |
|
| Customer managed policy | Reusable; ≤ 5 versions; one default version; roll back with SetDefaultPolicyVersion |
Managed = many + versions |
| Inline policy | Embedded in one identity; deleted with it; no versions | Inline = one-to-one |
| Freezing a managed policy | Deny iam:CreatePolicyVersion and iam:SetDefaultPolicyVersion |
|
iam:PassRole |
Permission, not an API → no CloudTrail event; checked when a role is handed to a service | No pass, no deploy |
Scoping iam:PassRole |
Role ARN(s) + iam:PassedToService (+ iam:AssociatedResourceArn); not iam:ResourceTag |
|
| Passed role's trust policy | Must name the receiving service principal (e.g. lambda.amazonaws.com) |
|
| PassRole across accounts | Not possible; use a role in the service's own account | |
| One role per workload | EC2 instance profile, Lambda execution role, ECS task role, CodeBuild service role | |
| ECS task roles on EC2 | ⚠️ Work out of the box on current ECS-optimized AMIs; ECS_ENABLE_TASK_IAM_ROLE=true only for other AMIs or external instances |
|
| Long-term access keys | ⚠️ Only where roles can't be used; humans → IAM Identity Center; workloads outside AWS → IAM Roles Anywhere or OIDC/SAML federation | Borrow credentials, don't own them |
AWS Directory Service
| Topic | Current facts | Memory hook |
|---|---|---|
| AWS Managed Microsoft AD | Real AD (Windows Server 2019) in 2 AZs; Standard ~30,000 / Enterprise ~500,000 objects; trusts; RADIUS MFA; RDS for SQL Server | Real AD, run by AWS |
| AD Connector | Proxy to on-premises AD; no directory data in AWS; RADIUS MFA; seamless EC2 domain join | Connector = a cable |
| Simple AD | Samba 4, basic AD features; no trusts, MFA, LDAPS or schema extensions | Simple = standalone |
| Simple AD availability | ⚠️ Closed to new customers since 30 Jul 2026; existing customers keep it; newcomers use Managed Microsoft AD or AD Connector | |
| Managed Microsoft AD Hybrid Edition | ⚠️ Since 30 Jul 2025: extends a self-managed AD into AWS with the same identities | |
| Customer sign-up for apps | Amazon Cognito, not Directory Service |
Numbers to know
| Item | Value | Note |
|---|---|---|
| ID and access token validity | Default 1 h; 5 min–1 day | Per app client |
| Refresh token validity | Default 30 days; 1 h–3,650 days | Per app client |
| Refresh token rotation grace period | Up to 60 s | ⚠️ Rotation is optional |
Authentication session (AuthSessionValidity) |
3–15 min | Time to answer each challenge; default ⚠️ unverified |
| Managed login session cookie | 1 h | Cleared by /logout |
| Sign-up confirmation code | 24 h | ResendConfirmationCode for a new one |
| Forgot-password code | 1 h | |
| MFA code validity | 3–15 min | |
| Lambda trigger response time | 5 s, not adjustable | Synchronous triggers |
| Custom attributes per user pool | 50 | Not adjustable |
| User pools per Region | 1,000 | Adjustable to 10,000 |
| App clients per user pool | 1,000 | Adjustable to 10,000 |
| Users per user pool | 40,000,000 | Adjustable |
| Client secrets per app client | 2 | For rotation |
UserAuthentication request quota |
120 RPS | Adjustable; sign-in + refresh |
UserCreation request quota |
50 RPS | Adjustable |
ClientAuthentication (client credentials) quota |
150 RPS | Not adjustable → cache M2M tokens |
| Built-in Cognito email sender | 50 emails per day per account | Use SES for production |
| Custom domains per Region | 4 | Certificate in us-east-1 |
| Callback URLs per app client | 100 | |
| Identity pool enhanced-flow credentials | 1 h | |
| Identity pools per account | 1,000 | Adjustable |
| Role-mapping rules per identity provider | 25 | Not adjustable |
GetId / GetCredentialsForIdentity rate |
25 RPS / 200 RPS | Cache the identity ID |
ALB authentication SessionTimeout default |
604,800 s (7 days) | |
| ALB sign-in completion limit | 15 min | Then HTTP 401 |
| ALB user claims + access token size | 11 KB | Above → HTTP 500 |
ALB jwt-validation JWKS limits |
≤ 150 KB, ≤ 10 keys; ≤ 10 extra claims | ⚠️ New Nov 2025 |
AssumeRole session duration |
900 s up to the role maximum; default 3,600 s | ⚠️ Not "1 hour max" |
Role MaxSessionDuration |
1–12 h | ⚠️ |
| Role chaining session | 1 h maximum | Asking for more fails |
GetSessionToken / GetFederationToken (IAM user) |
900–129,600 s (36 h); default 43,200 s (12 h) | Root: max 3,600 s |
AssumeRoot session |
≤ 900 s | ⚠️ New Nov 2024 |
| Session policies | 1 inline + 10 managed ARNs, 2,048 chars combined | |
| Session tags | 50; key 128 chars, value 256 chars | |
| External ID / role session name length | 2–1,224 / 2–64 characters | |
| STS request quota | 600 RPS per account per Region | Shared across STS calls |
| Managed policies per role / user / group | 20 (→25) / 10 (→20) / 10 | ⚠️ Role default was 10 |
| IAM policy size limits | Inline: user 2,048, group 5,120, role 10,240 chars; managed 6,144 chars | Whitespace not counted |
| Managed policy versions / role trust policy length | 5 versions / 2,048 chars (→ 8,192) | ⚠️ Trust max was 4,096 |
Decision rules
- If you see app users who need sign-up, sign-in or social/SAML login, think Cognito user pool.
- If you see temporary AWS credentials for app users or guests, think Cognito identity pool.
- If you see "sign users in, then let them call S3 or DynamoDB directly", think user pool + identity pool.
- If you see a backend that must trust a Cognito JWT, think verify signature with the JWKS plus
exp,iss, audience andtoken_use. - If you see scope-based API authorization, think access token; identity claims, think ID token.
- If you see "Unable to verify secret hash for client", think
SECRET_HASHfor a client with a secret. - If you see sign-up without a confirmation code, think pre sign-up trigger
autoConfirmUser. - If you see custom claims or scopes in access tokens, think pre token generation
V2_0on Essentials or Plus. - If you see a legacy user store to migrate without password resets, think migrate user trigger +
USER_PASSWORD_AUTH. - If you see a trigger failing after an IaC deployment, think the missing Lambda permission for
cognito-idp.amazonaws.com. - If you see a custom sign-in domain, think ACM certificate in us-east-1 + DNS alias to Cognito's CloudFront.
- If you see a browser app that needs refresh tokens securely, think authorization code grant with PKCE.
- If you see service-to-service tokens, think client credentials grant with custom scopes.
- If you see risk-based MFA or breached-password blocking, think Plus plan threat protection, audit mode first.
- If you see sign-in required in front of a web app with no code changes, think ALB
authenticate-cognito/authenticate-oidcon HTTPS. - If you see a target trusting ALB user headers, think verify
x-amzn-oidc-data(ES256,signer). - If you see guests failing on a service their role allows, think enhanced-flow guest scope-down policy.
- If you see different roles per user group, think group role + "choose role from token" in the identity pool.
- If you see access to another account's resources without keys, think cross-account role +
sts:AssumeRolefor the caller. - If you see a vendor that assumes roles in customer accounts, think
sts:ExternalId. - If you see a session longer than 1 hour rejected, think the role's
MaxSessionDurationor role chaining. - If you see MFA-protected CLI work for an IAM user, think
aws sts get-session-token --serial-number --token-code. - If you see a no-MFA deny that misses access-key calls, think
BoolIfExistsinstead ofBool. - If you see an explicit deny in any evaluated policy, think the request is denied.
- If you see cross-account access failing, think both the identity policy and the resource or trust policy must allow.
- If you see one policy for many users' folders, think
${aws:username}(IAM users) or principal tags (roles). - If you see
iam:PassRolein anAccessDenied, think PassRole on that role ARN withiam:PassedToService. - If you see reusable permissions with history and rollback, think customer managed policy versions.
- If you see on-premises AD users needing AWS apps with no data in AWS, think AD Connector.
- If you see AD trusts or RDS for SQL Server Windows authentication, think AWS Managed Microsoft AD.
Memory hooks
- User pool → tokens; identity pool → AWS keys.
- Authenticate at the user pool, authorize at the identity pool.
- ID token says who, access token says what.
- Decoding is not verifying: check the signature first.
- SRP = Secret Remains Private (the password never leaves the client).
- Secrets live on servers: public clients have no client secret.
- Update = replace: omitted Cognito settings fall back to defaults.
- Pre sign-up pre-approves; pre token generation is the last stop before tokens.
- Migration needs the password: no migrate trigger with SRP.
- Five seconds or fail: triggers are synchronous.
- The custom-domain certificate lives in Virginia (us-east-1).
- Code + PKCE for public apps; machines get access tokens only.
- Plus protects: threat protection needs the Plus plan.
- At the ALB, only the data header is signed.
audsays which identity pool,amrsays authenticated or guest.- Both doors open: trust policy and caller permission for cross-account roles.
- A role chain lasts one hour.
- If it doesn't exist, it isn't MFA: use
BoolIfExistsin denies. - Deny first, then every gate must say yes.
- Guardrails cap, never grant (SCP, RCP, boundary, session policy).
- Usernames are for users: no
${aws:username}for roles. - Inline is one-to-one; managed is many with versions.
- No pass, no deploy:
iam:PassRoleon the role ARN. - Connector = a cable to on-premises AD; Simple AD = standalone and closed to newcomers.