Your coding-agent console needs to list S3 artifacts, start a Batch review job, or invoke an API Gateway tool endpoint. Baking AKIA… into the SPA is how you get a GuardDuty finding and a bad week. Amazon Cognito Identity Pools (federated identities) trade a proven user/IdP token for temporary STS credentials bound to IAM roles — humans and UI-driven agent callers get least privilege that expires. Distinct from IAM Roles Anywhere (X.509 for on-prem/machine runners), AppSync subscriptions auth (Cognito user pools as GraphQL authorizer), and VPC Lattice service auth (service-to-service): here we mint AWS creds for tool callers via Identity Pools.
⚡ TL;DR: Authenticate humans with a Cognito User Pool (or OIDC IdP), attach an Identity Pool that maps authenticated role vs guest deny, scope IAM to specific tool APIs/S3 prefixes, and refresh via the Amplify/AWS SDK credential chain. Related: IAM Roles Anywhere, VPC Lattice service auth, API Gateway + WAF rate limits, Verified Permissions.
Identity Pools vs User Pools (stop mixing the terms)
| Piece | Job |
|---|---|
| User Pool | Sign-up/sign-in, JWT for your app APIs |
| Identity Pool | Exchange JWT (or public provider token) → AWS credentials |
| IAM role (authenticated) | What those creds may call |
| IAM role (unauthenticated) | Usually deny-all for coding-agent consoles |
❌ Using only a User Pool access token against AWS APIs that require SigV4 — you need Identity Pool (or a backend that proxies).
Browser
→ User Pool Hosted UI / OIDC
→ JWT
→ Identity Pool GetId + GetCredentialsForIdentity
→ temporary AWS keys
→ SigV4 to API Gateway / S3 / execute-api
Wire an Identity Pool for the coding-agent console
# ✅ identity pool with Cognito User Pool authentication providers
aws cognito-identity create-identity-pool \
--identity-pool-name coding_agent_console \
--allow-unauthenticated-identities \
--cognito-identity-providers \
ProviderName=cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC,ClientId=clientid123,ServerSideTokenCheck=true
# Prefer allow-unauthenticated-identities=false for agent consoles
Map roles:
aws cognito-identity set-identity-pool-roles \
--identity-pool-id us-east-1:guid \
--roles authenticated=arn:aws:iam::111122223333:role/CodingAgentConsoleAuth,unauthenticated=arn:aws:iam::111122223333:role/CodingAgentConsoleDeny
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "InvokeToolApi",
"Effect": "Allow",
"Action": ["execute-api:Invoke"],
"Resource": [
"arn:aws:execute-api:us-east-1:111122223333:apiid/*/POST/tools/*",
"arn:aws:execute-api:us-east-1:111122223333:apiid/*/GET/sessions/*"
]
},
{
"Sid": "ReadOwnArtifacts",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::coding-agent-artifacts-prod",
"arn:aws:s3:::coding-agent-artifacts-prod/tenant/${cognito-identity.amazonaws.com:claims.tenant}/*"
],
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/tenant": "${cognito-identity.amazonaws.com:claims.tenant}"
}
}
},
{
"Sid": "DenyBedrockDirect",
"Effect": "Deny",
"Action": ["bedrock:*"],
"Resource": "*"
}
]
}
Force tool calls through your API (Cedar/Verified Permissions) instead of letting the browser hit Bedrock directly — Identity Pool creds should be narrow.
Browser / gateway credential provider
// ✅ Amplify v6 / fromCognitoIdentityPool pattern (illustrative)
import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers";
import { SignatureV4 } from "@smithy/signature-v4";
const credentials = fromCognitoIdentityPool({
clientConfig: { region: "us-east-1" },
identityPoolId: "us-east-1:guid",
logins: {
"cognito-idp.us-east-1.amazonaws.com/us-east-1_ABC": idTokenJwt,
},
});
// Use credentials with API Gateway SigV4 or AWS SDK clients
// ❌ process.env.AWS_SECRET_ACCESS_KEY in Vite bundle
For server-side agent gateways calling on behalf of a user, prefer backend assumes a role with the user’s identity in context (or Identity Pool on the server with the user’s JWT) — never forward long-lived keys to the model context.
Principal tags and tenant isolation
Pass tenant claims into the Identity Pool role session with principal tags so IAM conditions work:
# role trust policy fragment — allow Cognito identity to assume with tags
{
"Effect": "Allow",
"Principal": { "Federated": "cognito-identity.amazonaws.com" },
"Action": ["sts:AssumeRoleWithWebIdentity", "sts:TagSession"],
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:guid"
},
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
}
Map custom attributes (custom:tenant_id) via rules. Combine with Access Analyzer reviews so the authenticated role does not slowly accrete * powers.
When not to use Identity Pools
| Caller | Prefer |
|---|---|
| On-prem / CI machine runner | IAM Roles Anywhere |
| Service → service inside VPC | VPC Lattice auth / IAM SigV4 mesh |
| GraphQL subscriptions only | AppSync + User Pool JWT (AppSync progress) |
| Overnight Batch jobs | Job role on the Batch job definition — no Cognito |
Rate-limit public execute-api with WAF. Watch for stolen JWTs with GuardDuty.
Failure modes
| Issue | Symptom | Mitigation |
|---|---|---|
| Unauthenticated enabled | Anonymous AWS calls | Disable unauth; deny role |
| Overbroad authenticated role | Browser can bedrock:InvokeModel |
Deny Bedrock; proxy via API |
| Missing TagSession | Tenant conditions fail open/closed | Require sts:TagSession; test |
| Token in localStorage XSS | Session theft | HttpOnly patterns / short TTL / CSP |
| Confused IdP | Wrong user pool client | ServerSideTokenCheck=true |
Production checklist
- [ ] User Pool (or enterprise OIDC) for humans; Identity Pool for AWS creds
- [ ] Unauthenticated identities disabled for agent consoles
- [ ] Authenticated role least privilege; explicit Deny on Bedrock if proxied
- [ ] Tenant principal tags + S3/API conditions tested
- [ ] No long-lived keys in frontend bundles or agent prompts
- [ ] WAF rate limits on tool APIs; Cognito advanced security optional
- [ ] Distinct from Roles Anywhere / Lattice / AppSync user-pool-only auth
- [ ] Access Analyzer + periodic role review
- [ ] Document token TTL / refresh UX
FAQ
Q: Identity Pool or just exchange code for API Gateway JWT authorizer?
A: If every AWS call is behind your HTTP API, a JWT authorizer may be enough — no AWS creds in the browser. Use Identity Pools when the client must SigV4 to AWS (S3 direct, execute-api IAM, AppSync IAM mode).
Q: Can agents themselves use Identity Pools?
A: UI-driven and user-delegated callers yes. Headless Batch/ECS workers should use task/job roles. Don’t put Cognito user passwords in agent tool configs.
Q: Guest access for demos?
A: Separate demo pool with tiny quotas and kill-switch — never the prod authenticated role with a “temporary” Allow.
Related reading
- IAM Roles Anywhere: Cert Creds for On-Prem Runners
- VPC Lattice: Service Auth for Tool Microservices
- AppSync GraphQL Subscriptions for Progress
- API Gateway + WAF Rate Limits
Federate the human. Mint temporary creds. Keep AKIA out of the SPA — and out of the model’s mouth.
Last updated on October 4, 2026
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
- Java Virtual Threads vs Traditional Threads: What Nobody Tells You
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Config Coding Agents Must Not Hardcode
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena: Query Coding-Agent Tool Audit Logs Without a Warehouse
- AWS Batch: Overnight Parallel Coding-Agent Jobs Without Babysitting EC2
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.