Skip to content

Agent security

AI Agent Identity: Who Acts, and on Whose Behalf

Give each AI agent its own identity, use delegation not impersonation, and keep tokens narrow. Patterns for Google Cloud, AWS, Microsoft, Anthropic and OpenAI.

Picture the alert that opens an incident review. AI agent identity is the set of credentials and rules that tell every system which agent is acting and, when the agent acts for someone, which person it acts for. Overnight, a support agent issued a run of refunds. The scenario is illustrative, not a client story. The billing system's audit log shows the same name on every line: svc-agent-prod. Which engineer asked for those refunds? Did anyone ask at all, or did the agent act on its own? Was it allowed to refund that much? The log cannot say, because every person who ever used the agent, and the agent itself, signed in as one service account.

A shared service account cannot answer those questions, and the major cloud platforms now treat agent identity as a problem of its own. This note sets out what a production agent's identity should look like, using one support agent as the example throughout.

Every action an agent takes should carry two names: the agent that did it, and the person it did it for.

If you read only this:

  • Give each agent its own identity, not a shared service account and not a borrowed user account.
  • When an agent acts for a person, use delegation, not impersonation. The token names the person as the subject and the agent as the actor.
  • Make every token narrow. It should be good for one server, one set of scopes and a short time, and the agent's code and the model should never hold a long-lived secret.

Why a shared service account fails for agents

Think of a letter an assistant signs for a manager: "A. Rao, for M. Iyer". Anyone reading it knows who held the pen and whose authority it carries. A shared service account is a letter signed only "the office". It fails an agent in three ways.

  • Attribution. Every action looks the same in the log, whether a person asked for it, a schedule triggered it, or an injected instruction did.
  • Over-privilege. The account needs the union of everything any user might ask for. A junior engineer's request runs with the rights meant for the most senior user.
  • Revocation. You cannot switch off one misbehaving agent, or one user's access through it, without breaking everyone else.

OWASP's Top 10 for Agentic Applications for 2026 names this risk outright: ASI03, Identity and Privilege Abuse. NIST's National Cybersecurity Center of Excellence (NCCoE) is scoping a possible project on it. The NCCoE's February 2026 concept paper on software and AI agent identity and authorization lists the areas to explore: identification, authorization, access delegation, and logging and transparency. It also asks how to handle "on behalf of" scenarios. It is a draft concept paper, not guidance yet, but the questions are the right ones.

Two modes: acting for a person, or acting for itself

Our support agent does two kinds of work. During the day, an engineer asks it to look up a customer's order and, when warranted, issue a refund. At night, it sweeps stale tickets and closes the ones with no reply. Nobody asks it to.

These are different identity situations, and the platforms now name them separately.

Table: Two modes: acting for a person, or acting for itself
ModeExampleWhose authorityTypical OAuth flow
On behalf of a person"Refund order 1182" from an engineerThe person's, exercised by the agentAuthorization code (user consent) or token exchange
AutonomousNightly ticket sweepThe agent's ownClient credentials

Microsoft Entra Agent ID ships separate Conditional Access templates for agents acting on behalf of users and for autonomous agents, as What's new in Microsoft Entra Agent ID lists. Amazon Bedrock AgentCore Identity, according to AWS's Features of AgentCore Identity page, supports both the client credentials grant (machine-to-machine) and the authorization code grant (user-delegated access). Google's What's new in IAM post says its Agent Identity lets you "recognize agents whether they are operating autonomously or on behalf of a user."

Two modes, one agent identity. The tool checks every token, and the audit record names the agent, the person and the grant.

The question to ask on every call is the one in the middle of the figure: is a person behind this request? If yes, the agent may do only what that person may do, and less if you choose. If no, it may do only what the agent itself has been granted. The two sets of rights should never merge into one account.

Give each agent its own workload identity

The first step is an identity that belongs to the agent alone. On Google Cloud, that identity now exists as a first-class IAM principal, separate from users and service accounts. Agent Identity gives each agent a cryptographic identity based on the SPIFFE standard (Secure Production Identity Framework For Everyone), tied to the resource where the agent is hosted. Google's Agent Identity overview draws the contrast with service accounts directly. Agent identities are not shared by multiple workloads by default, cannot be impersonated, and do not allow long-lived keys. Access tokens for Google Cloud are cryptographically bound to the agent's own X.509 certificate, to protect against token theft.

Agent Identity is generally available for Agent Runtime and in preview on Gemini Enterprise Agent Platform (Google describes it as an evolution of Vertex AI). You can write IAM allow and deny policies against it. A Principal Access Boundary (in preview) sets hard limits on what an agent may ever reach, whatever else it is granted.

The other platforms take the same shape:

  • AWS. AgentCore Identity keeps an agent identity directory. Each agent is a workload identity with its own ARN, so policy can target one agent or a group.
  • Microsoft. Entra Agent ID creates agent identities from a blueprint, as Microsoft's fundamental concepts page explains. The blueprint holds the credentials, and the agent identity itself has none of its own. Agent identities carry a sponsor, the person accountable for the agent, and lifecycle workflows hand sponsorship on when that person changes role or leaves.
  • Anthropic and OpenAI. Their model APIs do not issue identities to your agents. The identity lives in your cloud or identity provider, and the API call carries the token your system obtained.

Delegation, not impersonation

When the engineer asks for a refund, the agent needs a token for the billing system. The tempting shortcut is to forward the engineer's own token. Do not. A forwarded token makes the agent indistinguishable from the engineer, which is impersonation: in the letter analogy, the assistant signing the manager's name. The Model Context Protocol (MCP) forbids the pattern outright in its security best practices. A server must not accept tokens that were not issued for it, and must not pass them on.

OAuth already has the right tool. RFC 8693, OAuth 2.0 Token Exchange, draws exactly this line. Under impersonation, the receiver sees only the person. Under delegation, the agent "still has its own identity separate from" the person, and the token can say so in an act (actor) claim. The agent presents two tokens, the person's and its own, and asks the authorization server for a new one aimed at one resource:

POST /oauth2/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&subject_token=<the engineer's access token>
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
&actor_token=<the agent's own token, from its workload identity>
&actor_token_type=urn:ietf:params:oauth:token-type:jwt
&resource=https://billing-mcp.example.com/mcp
&scope=refunds:read

The body is shown on separate lines for reading; on the wire it is one URL-encoded form, and the agent also authenticates itself as an OAuth client, which is left out here. If the authorization server allows this agent to act for this person, and it issues JSON Web Token (JWT) access tokens with delegation claims, the new token's claims could look like this (illustrative values):

{
  "iss": "https://auth.example.com",
  "sub": "engineer:priya",
  "act": { "sub": "agent:support-assistant" },
  "aud": "https://billing-mcp.example.com/mcp",
  "scope": "refunds:read"
}

Whether you get a token shaped like this depends on the implementation, not on the standard alone. RFC 8693 says that when and if such a composite token is issued "is at the discretion of the authorization server and applicable policy and configuration", and it defines the act claim for JWTs and for token introspection responses; sub itself comes from the JWT standard (RFC 7519), where it is optional. So whether an act claim appears, what your provider puts in sub, and whether you read them from a JWT or from the server's introspection endpoint depend on the provider and how you configure it. Do not assume every provider emits these claims automatically.

The example token is the letter signed "A. Rao, for M. Iyer". It names the person, names the agent, works at one server and carries one scope. Give it a lifetime of minutes. The authorization server decides, from its own policy, which agents may act for which people; RFC 8693 defines a may_act claim for stating exactly that. Two cautions apply. Not every identity provider supports token exchange at all, so check yours, and its configuration, before designing around it. Agent-specific extensions to OAuth exist only as individual Internet-Drafts; the on-behalf-of user authorization for AI agents draft, for example, has expired. RFC 8693 itself is a published standard, so build on that.

Short-lived, audience-bound, narrowly scoped tokens

MCP's 2026-07-28 authorization specification turns most of this into rules for agents that call tools over HTTP:

  • One audience per token. Clients must send the resource parameter (RFC 8707) naming the server's canonical URI, and servers must check that a token was issued for them.
  • No passthrough. Clients must not send a server any token except one issued by that server's authorization server.
  • Least scope first, more on demand. A server signals missing scope with 403 insufficient_scope. A client acting for a user should then attempt step-up authorization, asking for the union of the scopes it had and the scopes it now needs, and retry only a few times.
  • Client identity without open registration. Dynamic Client Registration is deprecated in favour of Client ID Metadata Documents: the client's ID is an HTTPS URL that serves its metadata. When an authorization response carries an iss value, clients must check it against the issuer they expected.

Step-up gives our support agent a natural shape. It starts with refunds:read. When the engineer asks for an actual refund, the billing server answers insufficient_scope, and the engineer is asked to grant refunds:create.

Delegation with step-up. The agent starts with read-only rights and gains the write scope only when the person grants it.

Step-up is not the same as approving the action. A consent screen grants a scope such as "create refunds", not "refund 40 euros on order 1182". For consequential actions, keep a separate approval step that shows the concrete action, as described in our note on autonomy tiers and human approval.

On the receiving side, the check is short. It runs after the token's signature, issuer and expiry are verified, and it is the code every MCP server or internal API should run before it acts:

CANONICAL_URI = "https://billing-mcp.example.com/mcp"  # this server's canonical URI
KNOWN_AGENTS = {"agent:support-assistant"}            # from your agent registry

def authorize(claims: dict, required_scope: str) -> str:
    """Run only after the token's signature, issuer and expiry have been verified."""
    aud = claims.get("aud")
    audiences = aud if isinstance(aud, list) else [aud]
    if CANONICAL_URI not in audiences:
        raise PermissionError("token was not issued for this server")
    if required_scope not in claims.get("scope", "").split():
        raise PermissionError(f"insufficient_scope: {required_scope}")
    actor = claims.get("act", {}).get("sub")
    if actor is not None and actor not in KNOWN_AGENTS:
        raise PermissionError("unregistered agent acting for this user")
    return f"user={claims['sub']} agent={actor or 'none'} scope={required_scope}"

The returned string is the audit line the incident review was missing.

Scopes say what kind of action an agent may take, not how much. The largest refund an agent may issue for a given engineer is a policy rule. Check it at the tool or at a gateway, with the person and the agent from the token as inputs. That answers the incident review's last question.

Keep secrets out of the model's reach

An agent's tokens should live where the model never sees them, and where as little of your own code as possible can read them. Anything placed in the model's context can be repeated back out, for example under a prompt injection. Every platform now offers a place for these secrets:

  • Google Cloud. The Agent Identity auth manager is a credentials vault and authentication broker that runs the three-legged OAuth flow for agents acting on behalf of users. It is in preview.
  • AWS. The AgentCore Identity token vault stores OAuth tokens, client credentials and API keys encrypted with KMS. It releases them only to agents that present proof of workload identity.
  • Anthropic. Claude Managed Agents (beta) keeps a vault per end user, referenced when a session is created, as Anthropic's vaults documentation describes. For environment-variable secrets the sandbox holds only a placeholder, and the real value is substituted at egress, so "the agent never sees the secret value." Substitution is outbound only: a token returned by an exchange made inside the sandbox arrives there unredacted. Anthropic's advice is to perform the exchange yourself and store the resulting token in the vault.
  • OpenAI. According to OpenAI's MCP servers guide, the Responses API takes an authorization field on the MCP tool and does not store it. Your backend keeps the token and sends it with every request.
Where the token lives. The model chooses the call; the runtime attaches the credential; the token never enters the context window.

Both API-level MCP integrations, Anthropic's MCP connector and OpenAI's MCP tool, take a token your application has already obtained. Anthropic's MCP connector documentation says so directly: API consumers are expected to handle the OAuth flow. That is where the delegation design above belongs.

Where each platform puts these pieces

Table: Where each platform puts these pieces
PlatformThe agent's own identityActing for a personWhere tokens live
Google CloudAgent Identity, SPIFFE-based, one per agentThree-legged OAuth through the auth manager (preview)Agent Identity auth manager
AWSAgentCore Identity workload identity with its own ARNAuthorization code grant through credential providersAgentCore Identity token vault
MicrosoftEntra Agent ID agent identity, created from a blueprintOn-behalf-of flow with delegated permissionsBlueprint credentials, used through the Entra Auth SDK sidecar
Anthropic APIComes from your platformYour app runs OAuth; Managed Agents vaults hold per-user credentialsManaged Agents vaults (beta), or your own store
OpenAI APIComes from your platformYour app runs OAuthYour backend; the API does not store the token

Standard pattern, provider support, vendor-specific part

Some of the above is standard and some is one vendor's design. The table separates them. Status is what each provider's own documentation or announcement says; where a page states no launch stage, the table says so rather than guess.

Table: Standard pattern, provider support, vendor-specific part
PatternStandardWhat the providers documentVendor-specific
Agent acts on its ownOAuth 2.0 client credentials grant (RFC 6749, section 4.4)AWS AgentCore Identity: client credentials grant (the features page states no launch stage). Microsoft Entra Agent ID: client credentials flow for autonomous agents (generally available). Google Agent Identity: 2-legged OAuth (Agent Runtime generally available, Agent Platform in preview, per Google's 7 May 2026 post)The agent identity object itself: Google's SPIFFE-based principal, Entra's blueprint-created identity, AWS's workload identity ARN
Agent acts for a person, with the person's consentOAuth 2.0 authorization code grant (RFC 6749, section 4.1); sign-in via OpenID Connect, an identity layer on OAuth 2.0AWS: authorization code grant. Google: 3-legged OAuth through Agent Identity Auth Manager (preview). Microsoft: delegated permissions for interactive agentsCredential vaults and brokers: AgentCore token vault, Google's auth manager, Entra's Auth SDK sidecar
Delegation chain: a new token for one resource, naming person and agentRFC 8693 token exchange with the act claimThe AgentCore, Entra Agent ID and Google Agent Identity pages checked do not name RFC 8693. Microsoft documents its own on-behalf-of flow; AWS documents an "impersonation flow" using credentials provided to the agentEntra's on-behalf-of request uses the JWT bearer grant type (urn:ietf:params:oauth:grant-type:jwt-bearer) with a Microsoft parameter, requested_token_use=on_behalf_of, which is not RFC 8693's request shape. Whether any given token carries act is the provider's choice
Token format your API can verifyRFC 7519 JWT; RFC 9068 profile for JWT access tokensMicrosoft warns not to read or validate tokens for APIs you do not own, because they may not be JWTsRFC 9068 requires iss, sub, aud, client_id, exp, iat and jti, and does not define act; claims beyond that are the provider's

Reading across: the grant types for an agent's own work and for user consent are standard and widely documented. The delegation shape this note recommends, RFC 8693 with an act claim, is a standard, but on the pages checked no provider names it for agents, and Microsoft's on-behalf-of flow is its own variant. Treat any claim that "the token names the agent" as a property of one provider's configuration until you have decoded a real token from yours.

Honest limits

  • Identity does not stop prompt injection. An agent tricked by a poisoned document still holds valid tokens. Good identity limits what the trick can reach and records who it acted for. It does not make the trick fail.
  • The standards are still settling. RFC 8693 is stable. Agent-specific OAuth drafts are not standards, NIST's work is at the concept-paper stage, and MCP expects a future revision to require authorization servers to include iss (today a SHOULD).
  • Downstream systems may not cooperate. Many SaaS APIs accept only their own OAuth tokens and know nothing of an act claim. Then you store a per-user token in a vault and record the actor in your own audit trail, not in the token.
  • Previews are previews. Google's auth manager and Agent Identity on Agent Platform, and Anthropic's Managed Agents vaults and MCP connector, were not generally available on 27 October 2026. Check their status before you commit a design to them.
  • More identities mean more to govern. One identity per agent multiplies the grants you must review. Sponsors and registries are how that stays manageable.

Takeaways

  • One agent, one identity. Never a shared service account; never a human's account.
  • Two names on every delegated action. The person as subject, the agent as actor, through token exchange, not forwarding, where your authorization server supports it.
  • Narrow tokens. One audience, least scope, short life, step-up for more.
  • Secrets outside the model. A vault or auth manager attaches credentials; the context window never holds them.

Reread-me checklist

  • Every production agent has its own identity, and no agent signs in as a person.
  • Each tool call is classified as on behalf of a person or autonomous, and uses the matching flow.
  • Delegated tokens carry the person as subject and the agent as actor.
  • Every token names one resource, and every server rejects tokens issued for another.
  • Scopes start minimal; writes need step-up, and consequential actions need a separate approval.
  • No user token is ever forwarded to a server it was not issued for.
  • Tokens and keys live in a vault or auth manager, never in prompts, code or environment files the agent can read.
  • Each audit record answers: which agent, for which person, under which grant, doing what.

What's next

Identity tells you who an agent is. The next question is how many agents you have and where they connect, which is the job of a registry and a gateway. That is the subject of our note on AI agent registries. For the approval side, see our note on autonomy tiers and human approval, linked above. For how MCP and A2A divide the work, see MCP vs A2A.

Tell us which system in your stack cannot accept a delegated token. That one system usually decides the whole design. If you would like a second pair of eyes on it, our agent security work starts with exactly that map.

Further reading

Agent identity products, preview labels and the drafts around these standards change quickly, so check each vendor's documentation, and your identity provider's configuration, before you build on them.

New guides by email

Get an email when we publish a new guide on building, running and securing AI agents. You can unsubscribe from any of our emails.

Signing up needs JavaScript, and with scripts switched off this form cannot send. You can follow new guides through the feed instead. Insights feed (RSS)

Building agents like these?

Aelsha Innovations designs, builds, secures and observes AI agents in production. A readiness assessment is the place to start.