AWS Builder Center
Agentic AI Identity anti-patterns and how Amazon Bedrock AgentCore solves them

Agentic AI Identity anti-patterns and how Amazon Bedrock AgentCore solves them

AI agents authenticate across five actors (user, app, agent, gateway, tools) — and most teams only configure the static half. This post covers six production identity anti-patterns, how Amazon Bedrock AgentCore solves each with dynamic runtime enforcement, and what your observability stack should (and shouldn't) be showing you.

AI agents sit between you and your enterprise systems. Every agent must authenticate each invocation: as whom, who allowed it, under what condition, and for how long?
You likely started with the first step: set up an  IAM  role or register an  OAuth  client. That covers the static part. Production agent systems also need dynamic identity: runtime policy evaluation, just-in-time token exchange, session-bound credentials, and interceptor-based access control. This post covers the six identity anti-patterns we see in production, how  Amazon Bedrock AgentCore  addresses each, why static configuration alone is insufficient, and what your observability stack should (and should not) show you.



What is agent identity?

In a traditional application, identity is binary: you authenticate, and the application acts on your behalf. In an agentic system, identity is a chain — multiple actors, each with their own credential, bound together by trust relationships.

Five actors

Actor
Role
Identity Type
User
The human who initiated the request
 OIDC 
/
 OAuth 
identity (JWT from IdP)
Application
The frontend or orchestration layer calling the agent
API key,
 IAM role 
, or OAuth client
Agent
The autonomous AI workload performing actions
Workload identity (own  client_id  +  client_secret )
Gateway
The infrastructure middleman routing and enforcing policy
Service identity (
 AgentCore Gateway 
+ interceptor chain)
Tools
The downstream APIs and resources the agent touches
Resource-specific credentials (scoped access tokens)

Identity bindings

What binds these actors together is not a single credential — it's a chain of delegated trust, expressed through different  OAuth 2.0  flows depending on the relationship:
The identity chain

Machine-to-Machine (M2M) — Agent authenticates as itself ( client_credentials   grant ). No user in the loop. Use for: service-to-service APIs, background jobs, scheduled pipelines.
Three-Legged OAuth (3LO) — User explicitly consents to the agent accessing their resources ( authorization_code   grant  +  PKCE ). The agent never sees the user's password. Use for: first-time access to email, calendar, files.
On-Behalf-Of (OBO) — Agent exchanges an inbound user token for a downstream resource token ( token_exchange  , RFC 8693 ). The resulting token carries composite identity:  sub=user ,  act=agent . Use for: accessing user-scoped resources without re-prompting consent.

Why this matters

Four questions determine whether your agent identity is functional:
  1. As whom? — The agent must have its own identity, distinct from the user
  1. Who allowed it? — Every action traces back to a consent event or policy decision
  1. Under what condition? — Credentials are scoped, time-bound, and session-linked
  1. For how long? — Tokens expire, sessions end, and revocation propagates instantly
If any of these can't be answered for a given request, you have an identity gap. The six anti-patterns below show where those gaps appear in production, and where in the chain (user → app → agent → gateway → tool) the failure occurs.

Classify first: the L0–L3 framework

Not every agent needs every control. The required identity posture depends on the agent's agency (what it can access) and autonomy (whether a human is in the loop):

Low autonomy (human-in-the-loop)
High autonomy (self-directed)
Low agency
L0 — Public info only. Inbound auth sufficient.
L2 — Pre-authorized, bounded by standing policy. Needs M2M + Token Vault + rotation.
High agency
L1 — User-consented. Needs 3LO + scoped tokens.
L3 — Broad access, delegates to sub-agents. Needs everything: OBO, Cedar policy, FGAC interceptors, delegation chain controls.
Higher agency demands stronger credential controls. Higher autonomy demands stronger policy enforcement. The anti-patterns below become progressively more dangerous as you move toward L3.



The six agent identity anti-patterns

Six agent identity anti-patterns


Anti-Pattern #1: Impersonation Instead of Delegation

The agent replays the user's access token directly against downstream APIs. No separate agent identity exists.
Scenario: An AI assistant obtains a user's Entra ID token and calls Microsoft Graph with it. Audit logs show the user sent 400 emails in 2 minutes — security flags it as account compromise. It was the agent. There's no way to distinguish or revoke agent access independently.
Impersonation vs delegation


The Fix: OBO Token Exchange with  AgentCore Identity 

OBO token exchange with AgentCore Identity

 AgentCore Identity  performs  RFC 8693  token exchange. The resulting token carries composite identity ( sub=user ,  act=agent ). Downstream services distinguish agent-initiated actions from direct user actions. You revoke the agent without touching the user's session.
Key API calls:
  1.  GetWorkloadAccessTokenForJWT  — binds user identity to agent workload
  1.  GetResourceOauth2Token(oauth2Flow=ON_BEHALF_OF_TOKEN_EXCHANGE)  — exchanges for downstream token

Anti-Pattern #2: Shared Credentials & Static Tokens

Multiple agents share one token, or tokens never expire. Secrets stored in code repos or env vars.
Scenario: 12 agents share one  svc-bot  Salesforce integration user. The token leaks from one agent's debug logs — all agents and all customer records are exposed. No attribution of which agent acted. Rotation breaks all 12 simultaneously.
The fix: Credential Providers + workload identity
Before
After (AgentCore Identity)
12 agents share one  client_id  +  client_secret 
Credentials live in a
 Credential Provider 
— agents never see them
Token created in 2022, never rotated
Agent receives a short-lived JWT (minutes). Underlying secret rotation is invisible to agents
Stored in  .env  or hardcoded
Agent authenticates to Credential Provider via its own workload identity
Compromise = total exposure (secret + all data)
* Compromise = total exposure (secret + all data)
The agent authenticates to the Credential Provider using its workload identity. The Credential Provider holds the actual  client_id  and  client_secret  — the agent never sees them, they're never logged, and they can't be leaked from agent code or debug output.
What the agent does see is the resulting JWT. That's the only thing that can leak. Blast radius: the JWT's TTL (minutes), scoped to whatever the Credential Provider issued it for.
A single Credential Provider can be shared across multiple agents — each agent proves its identity via its workload credentials, and the Provider decides what to issue. The underlying secret is managed, rotated, and audited in one place.
* To eliminate the compromise, AgentCore Gateway can broker the communication with downstream resources and handle credential exchange entirely with AgentCore Identity, so the agent sees only tool results and no auth tokens at all.

Anti-Pattern #3: Over-Scoped OAuth Grants

The agent requests  Mail.ReadWrite ,  Calendars.ReadWrite ,  Files.ReadWrite.All  when it only needs  Mail.Read . "Admin consent so it works."
Scenario: A compromised email-summarization agent's token exposes the user's full mailbox, calendar, and entire OneDrive — not just read access to email.

The Fix: Scoped  resourceOauth2Scopes  Per Tool

Python
@requires_access_token(
auth_flow="USER_FEDERATION",
scopes=["Mail.Read"] # minimum viable scope
)
def summarize_emails(user_id: str):
...

AgentCore enforces scope declarations at the tool level. Each tool specifies exactly what it needs. Incremental consent prompts only when a tool with additional scopes is invoked — not upfront.

Anti-Pattern #4: No Credential Isolation & No Revocation

All users' tokens in one flat table keyed by  user_id . Access tokens have 24-hour TTL. No mechanism to revoke before expiry.
Scenario: A user leaves. IT disables their Okta account. The agent holds a valid 24-hour token and continues operating at full access — because there's no revocation mechanism and no short TTL to limit the window.
The fix: Token Vault isolation + short TTL + forced re-authentication
Before
After (AgentCore Identity - Token Vault)
One flat table for all users
Composite key:  {agent_id}#{user_id}#{resource} 
Shared encryption key
Per-tenant KMS key
24-hour access tokens
5–15 minute TTL, auto-refreshed
No revocation mechanism
Short TTL +  forceAuthentication=true  to purge stored tokens
Terminated user → 24h exposure
Terminated user → minutes of residual access
Token vault invalidation

For immediate invalidation: Call   GetResourceOauth2Token   with  forceAuthentication: true . This clears the stored refresh token from the vault and forces a full re-authentication flow. If the user's IdP account is disabled, re-authentication fails — access is permanently revoked.
One-time-use refresh tokens add replay detection: a stolen refresh token can only be used once before it's rotated, limiting the window even further.

Anti-Pattern #5: Standing Access & No Session Binding

The agent authenticates via M2M ( client_credentials ) to access user-scoped data. It has permanent credentials — no user needs to be present.
Scenario: A data analytics agent holds a standing M2M token with  HR.Read.All  scope. It queries salary data at 3 AM with no user session. Audit shows "agent-xyz accessed HR API" but not on whose behalf.
The fix: OBO + principal-constrained Cedar policy
Structural fix: Replace M2M with OBO for user-scoped data. The agent calls   GetWorkloadAccessTokenForJWT   — no inbound user JWT = call fails = no downstream credentials exist.
Policy fix: Constrain the permit to  AgentCore::OAuthUser  — so even if someone grants the agent IAM access, Cedar blocks it:
plaintext
permit(
principal is AgentCore::OAuthUser,
action == AgentCore::Action::"HRTool___query_records",
resource == AgentCore::Gateway::"arn:aws:bedrock-agentcore:us-east-1:123456789012:gateway/my-gateway"
)
when {
principal.getTag("role") == "hr-analyst" &&
duration("8h") <= context.system.now.toTime() &&
context.system.now.toTime() <= duration("18h")
};
Three things happen:
  1.  principal is AgentCore::OAuthUser  — M2M calls present as  AgentCore::IamEntity , don't match this permit, fall to default DENY
  1.  principal.getTag("role")  — only hr-analysts, not any authenticated user
  1.  context.system.now.toTime()  — even with a valid token, denied outside 8–18h UTC
No user JWT = no OBO token = agent can't reach the Gateway with OAuth credentials. Standing access becomes structurally impossible.
For approval-gated workflows,  temporal policies (Dogwood)  can additionally require a prior approved action within the session before permitting sensitive operations.

Anti-Pattern #6: Uncontrolled Cross-Agent Delegation

Agent A delegates to Agent B with full permissions. No scope reduction exists at delegation boundaries.
Scenario: An orchestration agent delegates to a sub-agent which delegates again. The third-hop agent (meant for S3 reads) ends up with permissions to write production databases.

The Fix:  AgentCore Policy  + fine-grained access control via  AgentCore Gateway Interceptors  at every boundary

Gateway interceptor enforcement

 Cedar  policies enforce explicit authorization at each delegation hop.  Gateway interceptors  filter the tool list per agent. Every hop is logged with the complete delegation chain.



Static vs. dynamic identity: setting up IAM is half the story

Static vs dynamic identity

Most teams stop at the static layer. They configure IAM roles, register OAuth clients, define scopes, and set up IdP trust. This answers "who can access what." It does not answer "who should access what, right now, under these conditions."

Static layer (necessary, insufficient)

What it covers
What it misses
IAM execution role for the agent
Whether the agent should use it now
OAuth client registration
Per-request scope evaluation
Scope definitions
Runtime scope reduction per delegation
IdP trust (OIDC discovery)
Session-binding of credentials

Dynamic layer (where AgentCore operates)

  •  Cedar Policy  Evaluation — Evaluated on every Gateway request. Conditions include  time-of-day  ( context.system.now ), tool input parameters ( context.input.<field> ), and user attributes from the JWT ( principal.getTag() ).  forbid  always wins over  permit . Default = DENY. For rules that depend on what happened earlier in a session (e.g., requiring a prior approval),  Temporal Policies (Dogwood)  evaluate against session history — not the current request alone.
  •  Gateway Interceptors  — Lambda functions at the request/response boundary. Token exchange (swap Okta JWT for GCP token), interceptors (filter tools by JWT scopes), PII masking (redact before reaching LLM). No caching — real-time evaluation.
  • JIT Token Exchange ( OBO ) — The agent calls   GetResourceOauth2Token   to obtain a short-lived access token scoped to the declared permissions. Tokens are cached in the vault and auto-refreshed — the agent never holds the underlying  client_id / client_secret . If the Gateway is used to reach the resources instead, the agent never sees a token at all.
  • Session-Bound Credentials —  Token Vault  releases credentials only during active user sessions. No session = no tokens, regardless of what IAM or OAuth configuration allows.
OBO delegation flow


How this works in practice

AgentCore Gateway working together with AgentCore Policy and AgentCore Identity provides exactly this runtime evaluation layer lifting the responsibility from the developer to write the code for authentication or authorization as part of the agent logic:
AgentCore Gateway runtime flow




Observability of agent identity: what you should see, and what silence means

You don't get agent identity observability from a single dashboard. It's a shared responsibility between what AgentCore provides and what you build on top.

What ideal looks like

For every agent-initiated request, you should be able to answer:
which agent, acting for which user, called which tool, with what parameters, under what policy decision, and what was the outcome?
If you can't reconstruct that chain from your logs, you have blind spots.

What AgentCore provides

Signal
Source
What you see
Validates fix for
 Cedar policy language 
decisions (PERMIT / DENY)
CloudWatch Logs
Every policy evaluation: principal, action, resource, decision, and the conditions that matched
Over-scoped grants, standing access
AgentCore Identity API calls
CloudTrail
 GetWorkloadAccessToken ,  GetResourceOauth2Token  — which workload identity called, when, with what  oauth2Flow 
Impersonation, shared credentials
Policy enforcement mode
CloudTrail
 UpdateGateway  events — alerts you if someone switches from ENFORCE to
 LOG_ONLY 
mode
All anti-patterns (enforcement disabled = none are enforced)
Temporal policy session events
CloudWatch Logs
If you use
 Temporal Policies (Dogwood) 
, the policy engine logs session history and evaluation results
Approval-gated workflows

What you build yourself

Signal
How to build it
Validates fix for
Lifecycle-triggered token revocation
IdP webhook (Okta/Entra event) → Lambda → GetResourceOauth2Token ( forceAuthentication=true)
No isolation / revocation — active revocation on termination
Gateway interceptor audit logs
Your interceptor Lambda writes to CloudWatch: what was filtered, masked, or transformed per request
Uncontrolled delegation — scope reduction at boundaries
Downstream service attribution ( sub  +  act  claims)
Configure downstream services (MS Graph, Salesforce) to log token claims. The  act=agent  claim is in the OBO token — the downstream service decides whether to surface it.
Impersonation — proving delegation, not impersonation
Per-agent identity usage dashboards
Query CloudTrail for  GetResourceOauth2Token  grouped by workload identity. Alert if one identity serves multiple agents.
Shared credentials — limiting damage from a single compromise
Scope drift detection
Compare declared scopes in  @requires_access_token()  across deployments. Alert on scope additions without review.
Over-scoped grants — incremental scope creep

Red flags: what silence tells you

What's missing in your logs
What it means
Zero Cedar DENY events with policies in ENFORCE mode
Scopes may be too broad — agents never hit a boundary. Or policies aren't attached to the Gateway.
Only one workload identity across all agents in CloudTrail
Agents share credentials — no per-agent attribution and no way to limit damage from one compromise.
No  GetWorkloadAccessToken  / OBO calls in CloudTrail
Agent accesses user-scoped data via M2M — no user in the loop. Standing access not fixed.
No  forceAuthentication=true  calls after HR lifecycle events
No active revocation path. Terminated users retain access until token TTL expires passively.
No interceptor logs for multi-agent delegation flows
Scope reduction at delegation boundaries isn't instrumented — you can't verify it's happening.
 UpdateGateway  flipping mode to LOG_ONLY with no alert
Someone disabled enforcement — all policies evaluate but don't block.



Defense in depth: the full stack

Defense in depth

Every request traverses all layers. A failure at any single layer does not grant access — the next layer still evaluates independently. This is Zero Trust applied to agent identity.

Summary

Agent identity is a runtime discipline. The six anti-patterns in this post come from production incidents across enterprises deploying agentic AI.
  1. Delegate, never impersonate. Agents authenticate as themselves with verifiable user context.
  1. Enforce at runtime. Cedar policies and interceptors evaluate conditions per-request, not per-deployment.
  1. Observe the absence. If your dashboards show no DENY events, no delegation chains, and no session boundaries, you have standing access with no guardrails.
 Amazon Bedrock AgentCore  provides the infrastructure to enforce these principles without requiring you to write auth code. Identity is the platform's job — not the agent's.
To get started, explore the  Amazon Bedrock AgentCore Developer Guide  and try the  AgentCore Identity workshop . If you have questions or feedback, leave a comment on this post or reach out through the  AWS re:Post community .



References

Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article