Three patterns: service principal, on-behalf-of, task-scoped
Lesson 2 of 5 in Agent Identity, Auth, and Secrets.
Three patterns cover nearly every real agent, and mature systems run all three at once — one per class of tool call. The skill is knowing which one a given call needs, because using the wrong one is how privilege escalates quietly.
Agent as service principal
The agent is its own first-class principal: a service principal, workload identity or execution role that exists in your directory, holds its own scoped permissions, and is named in every log line. On Microsoft Entra an agent identity is documented as a special kind of service principal; on AWS, AgentCore agent identities are workload identities with specialized attributes, each with a distinct ARN in a central directory.
Use it for: the agent’s own resources — its vector index, its scratch bucket, its queue, its model endpoint. Anything that belongs to the agent as a system component rather than to a user.
Get right: one identity per agent (not per fleet), scoped to that agent’s job, with a named human owner. Entra models this explicitly as an optional sponsor — an accountable user or group — which is the difference between an inventory and an orphan list.
Failure mode: using the service principal for user data too. Then the agent reads everyone’s mailbox with its own authority and per-user access control silently stops existing.
On-behalf-of (delegation)
The user authenticates, consents, and the agent exchanges that user token for a downstream token that carries both parties: the subject is the user, the actor is the agent identity. OAuth 2.0 calls this token exchange; Microsoft calls the pattern On-Behalf-Of (OBO).
Use it for: anything scoped to a person — their mail, their files, their tickets, their calendar, their entitlements in your line-of-business app.
Get right: the effective permission must be the intersection of what the agent may do and what the user may do, and the downstream service must be able to see that an agent was the actor. Consent must be per-scope and revocable by the user.
Failure mode: collapsing OBO into impersonation by passing the raw user token through. It works on day one and destroys attribution forever.
Short-lived task-scoped credentials
The credential is minted for this task, this session, these resources, and expires in minutes. The agent never holds a standing key; a broker in the runtime issues one on demand and the agent’s copy dies with the session.
Use it for: high-value or irreversible actions, third-party API access, anything a long-lived key would make permanently exploitable.
Get right: short TTL, audience-restricted (usable only against the intended service), and bound to a task or session id so the audit trail links credential to work item. AgentCore mints workload access tokens per agent-plus-user and caches them keyed by that pair; Foundry Toolbox centralizes credential injection and token refresh so the agent never sees the underlying secret.
Failure mode: "short-lived" credentials with a 30-day lifetime and * audience. Then you have a long-lived key with extra steps.
An on-behalf-of chain for a single tool call
- User signs in and consents
The user authenticates to your front end and grants the agent specific, revocable scopes — not "all your data", and not a checkbox buried in onboarding.
- Front end invokes agent with user token
Inbound auth. The agent endpoint validates the token against the configured identity provider — audience, issuer, signature, expiry, allowed clients.
- Is this caller allowed to invoke this agent?
An authorizer decides invocation rights before any reasoning happens. AWS documents two inbound mechanisms for AgentCore: IAM SigV4 for callers inside the AWS boundary, and OAuth JWT bearer tokens validated against a configured IdP.
- Runtime exchanges it for a delegated token
Token exchange, not token forwarding. The result carries subject = user, actor = agent identity, and only the scopes this tool needs. On AgentCore the validated user token is exchanged for a workload access token; on Foundry a hosted agent uses OAuth 2.0 On-Behalf-Of.
- Downscope to this tool and this resource
Request the narrowest audience and scope set that completes the call — one API, one resource, minutes of lifetime. A broad token handed to a tool is a broad token available to an injected instruction.
- Agent scope ∩ user scope permits it?
The resource server enforces both sides. Agent-only authority would let any user aim the agent at data they cannot see; user-only authority would let the agent do anything the user can, including things you never intended it to do.
- Tool call executes against the resource
The credential never enters the model context. The runtime holds it, attaches it, and drops it.
- Emit audit record: agent version + subject + actor + task
Attribution is written at call time. Reconstructing it later from prose logs does not work — see the audit lesson.
- Deny and log
A denial is a signal, not just an error. Repeated denials from one agent are a strong indicator of injection or misconfiguration.
- Result returned; token expires
The classic security name for getting this wrong is the confused deputy: a privileged intermediary is tricked into using its authority on behalf of a caller who does not have that authority. Agents are the most confusable deputies ever built, because their instructions arrive as text and they read text from places you do not control — web pages, tickets, retrieved documents, tool results. Prompt injection is a confused-deputy attack delivered through content.
This is why ambient authority — permissions the agent simply has, standing, for everything — is the design to eliminate. If the agent’s ledger write is always available, an injected instruction only has to persuade the model to use it. If the ledger write requires a delegated token that only exists when a specific user asked for a specific transfer, the injected instruction has nothing to grab. Identity design and injection defense are the same work seen from two angles: shrink what the model can reach with authority it already holds.
Walk one tool call through the choice below. Notice how often the answer is not "give the agent a permission" but "get a credential that only exists for this task".
Which credential should this tool call use?
Interactive decision tree — outcomes:
- On-behalf-of, downscoped
Exchange the user token for a delegated token: subject = user, actor = agent identity, scopes narrowed to this call. Enforce the intersection of agent and user rights at the resource server, and log both parties. Never forward the raw user token.
- Brokered per-user credential, then on-behalf-of semantics
The user consents once; the runtime stores the resulting OAuth tokens in a vault keyed to (agent, user) and injects them per call — the pattern AgentCore Identity implements with its token vault, where user-specific credentials are documented as accessible only by the individual agent acting for that user. The agent code holds nothing; revoking one user’s consent revokes exactly that access.
- Short-lived task-scoped credential plus a gate
Mint a credential bound to this task id, audience-restricted to the one API, expiring in minutes — and put an approval gate in front of it if the action is irreversible. High-value authority that exists only while a human is watching cannot be harvested by an injected instruction an hour later.
- The agent’s own service principal
Correct and boring: the agent acts as itself against its own resources, with permissions scoped to that agent alone. Keep the identity per-agent, give it a named human sponsor, and prefer platform-issued short-lived credentials over any stored key.
- Stop — you are about to build a superuser bot
Unattended access to many users’ personal data with the agent’s own authority is exactly the design that makes one injection a tenant-wide breach. Options, in order of preference: pre-authorized per-user consent with per-user tokens (the vault pattern); a narrowly scoped copy of just the data the batch job needs; or a human-triggered run where the delegated token exists only during the run. If none is possible, the scope of the job needs to shrink.
Tool: Tool Permission Lab — Permission Lab lets you assemble an agent’s identity and scopes, then watch which injected instruction turns into a real action — and which one hits an empty hand.
Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.