A2A delegation
When one agent calls another, the second should act on behalf of the first — and the original user — without inheriting more authority than it needs. oauth.work issues delegated, on-behalf-of tokens narrowed at every hop, each carrying a chain naming who is acting for whom.
The chain
Section titled “The chain”User ──grants──▶ Agent A ──on-behalf-of──▶ Agent B ──DPoP token──▶ MCP toolEvery arrow is a real token exchange. Agent A holds a token the user consented to; to call Agent B it exchanges that token for a narrower one.
Token exchange
Section titled “Token exchange”RFC 8693. The requesting agent authenticates as itself and presents the subject’s token:
POST /tokenAuthorization: Basic <base64(agent_b:cs_…)>Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=<agent A's token>&subject_token_type=urn:ietf:params:oauth:token-type:access_token&scope=tool:search&resource=https://tools.acme.com/mcp{ "access_token": "eyJ…", "issued_token_type": "urn:ietf:params:oauth:token-type:access_token", "token_type": "Bearer", "expires_in": 300, "scope": "tool:search"}Delegated tokens live 5 minutes, not an hour. An on-behalf-of token should not outlive the task it was minted for.
The rules
Section titled “The rules”Four constraints are enforced at exchange time.
Only agents may exchange. The requesting client must be a registered
agent client. A web app or service client attempting an exchange gets
unauthorized_client.
Scopes only shrink. The granted scope is the intersection of what was requested, what the subject token holds, and what the requesting agent is registered for:
granted = requested ∩ subject_scopes ∩ agent_allowed_scopesIf nothing survives that intersection, the request fails with invalid_scope. An agent cannot gain
a capability by being delegated to.
No cross-tenant delegation. The agent and the subject token must belong to the same
organization. Otherwise: invalid_grant, “agent and subject belong to different organizations”.
The subject token must be ours, currently valid, and not revoked.
The actor chain
Section titled “The actor chain”The issued token keeps the original subject in sub and records the acting agent in act. The
immediate actor is outermost; earlier actors nest beneath it (RFC 8693 §4.1):
{ "sub": "usr_01J…", "client_id": "agent_b", "act": { "sub": "did:key:z6Mk…agent-b", "act": { "sub": "did:key:z6Mk…agent-a" } }, "scope": "tool:search", "aud": "https://tools.acme.com/mcp", "actor_type": "agent"}Read it outward-in: agent B is acting, on behalf of agent A, on behalf of user usr_01J…. A
resource server that wants to authorize on the immediate caller reads act.sub; one that wants to
attribute the action to a person reads sub.
Each hop adds one layer. Nothing is ever removed, so the full provenance of a call survives to the end of the chain.
Why it holds up
Section titled “Why it holds up”- Scopes only shrink, at every hop, by construction.
- Tokens are short. Five minutes limits the value of an intercepted delegated token.
- DPoP binding is preserved. Present a proof at exchange and the delegated token is bound to the requesting agent’s key.
- Audience binding. A delegated token minted for one tool server is refused by another.
- Every exchange is recorded. A
token_exchangedaudit event names the subject, the actor, the agent client, and the granted scope — and the delegation itself is persisted, so a misbehaving agent is attributable after the fact, not just in the moment.
Verifiable delegation
Section titled “Verifiable delegation”Plain OAuth proves delegation only to parties that trust the same authorization server. When agent B has to prove to a third party that it may act for the user, exchange the delegated token for a credential:
POST /credentials/issueAuthorization: Bearer <delegated token>
{ "format": "sd-jwt-vc" }Because the token carries act, the platform issues a DelegationCredential rather than an agent
identity credential:
{ "delegatedSubject": "usr_01J…", "actor": { "sub": "did:key:z6Mk…agent-b", "act": { "sub": "did:key:z6Mk…agent-a" } }, "organization": "org_01J…", "scope": "tool:search"}It is signed by the tenant key and verifiable against the tenant’s published DID document by anyone — which is the part plain OAuth cannot do. See verifiable credentials.
Agent discovery
Section titled “Agent discovery”The platform publishes an A2A AgentCard at /.well-known/agent-card.json (and the legacy
/.well-known/agent.json), describing its transport and the client-credentials security scheme, so
an A2A peer can discover how to authenticate before it has any configuration.