Skip to main content

Agent-to-Agent Delegation

An agent can hand a sub-task to another agent. It exchanges a token for a new one issued to the worker agent, narrowed to the sub-task, while keeping the original subject (the user, when a user started the chain). Each exchange records the acting agent in the act (actor) claim, and when several agents delegate in turn, that claim nests so the full path from the original subject to the last actor stays in the token.

The worker authenticates the exchange request, and the subject token sets sub. The actor token, when the request includes one, names the new actor in act. Without it, the worker itself is recorded as the actor. Earlier actors from a subject token that ThunderID issued stay nested beneath the new actor.

Configure the agents​

The agent that requests the exchanged token needs the token exchange grant, because the grant is checked against the client authenticating at the token endpoint. In the hand-off below that is the worker. The grant is available in either operating mode, so an agent does not have to be extended to act for a user to take part.

  • Console: on the requesting agent's Advanced tab, add the Token exchange grant.
  • API: add urn:ietf:params:oauth:grant-type:token-exchange to that agent's grantTypes.

Grant each worker only the scopes its sub-task needs, through its roles. See Groups and roles.

Delegate a task to a worker agent​

The worker requests its own token from the token endpoint, presenting the subject's token as subject_token and the acting agent's token as actor_token, and requesting a narrower scope:

bash
curl -X POST https://localhost:8090/oauth2/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-u '<WORKER_CLIENT_ID>:<WORKER_CLIENT_SECRET>' \
-d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
-d 'subject_token=<SUBJECT_ACCESS_TOKEN>' \
-d 'subject_token_type=urn:ietf:params:oauth:token-type:jwt' \
-d 'actor_token=<CALLING_AGENT_ACCESS_TOKEN>' \
-d 'actor_token_type=urn:ietf:params:oauth:token-type:jwt' \
-d 'scope=flights:search'

ThunderID enforces downscoping: the issued scope is always a subset of the subject_token scope, so a worker never gains authority the subject did not have. Bind the worker's token to a specific downstream API with a resource (RFC 8707), as shown in Agent Access on Behalf of Users. See Token Exchange for the full request and its parameters.

The issued token keeps the subject and records the agent passed as actor_token:

json
{ "sub": "<subject-id>", "act": { "sub": "<acting-agent-id>", "iss": "<issuer>" } }

The nested act claim​

When the issued token records an actor and the subject_token already records one, the earlier actor moves one level down, beneath the new outermost act. Suppose the first worker in the example above delegates part of its task to a second worker. The second worker presents the token the first worker received as the subject_token and the first worker's own token as the actor_token. The new token records both agents:

json
{
"sub": "<subject-id>",
"act": {
"sub": "<first-worker-id>",
"iss": "<issuer>",
"act": { "sub": "<primary-agent-id>", "iss": "<issuer>" }
}
}

The new actor is the subject of the actor_token. Without an actor_token, the client that authenticates at the token endpoint is recorded as the actor when it is an agent, or an application that enables includeActClaim. The earlier actors nested beneath it follow these rules:

  • When both tokens carry an act claim, ThunderID keeps the chain from the subject_token and drops the one from the actor_token.
  • When only the actor_token carries an act claim, that chain is kept beneath the new actor.
  • When the new actor is already the outermost actor of the subject_token, the issued token records it once at the head.
  • A subject_token from an external issuer contributes no earlier actors, because that issuer names its actors in its own namespace.

An application that is not an agent and does not enable includeActClaim records no actor when it exchanges a token without an actor_token. The issued token then has no act claim, and the actors in the subject_token are not carried forward. To keep them, pass the calling party's token as the actor_token.

A resource reads sub to apply the subject's permissions and the outermost act to identify the agent making the call. The nested act claims record each earlier agent. RFC 8693 treats them as informational only and excludes them from access control decisions.

Explore with AI

ThunderID LogoThunderID Logo

Product

DocsAPIsSDKs
© Copyright Linux Foundation Europe.For web site terms of use, trademark policy and other project policies please see https://linuxfoundation.eu/en/policies.