Delegation chain explorer

An orchestrator delegates to a sub-agent with token exchange

Alex asks an orchestrator agent for a report. The orchestrator holds a token for the documents API in Alex's name and hands part of the work to a research sub-agent. Each hop exchanges the token it holds for a narrower one with an act claim, so the API can see the whole chain of who acted for whom, and no hop can do more than the one before it.

AttackToken passthrough

The orchestrator hands Alex's original token to the sub-agent and the sub-agent presents it as is. No exchange, no act claim, full docs:write scope: the API sees Alex, cannot tell which agent is calling, and a sub-agent that goes wrong can write and delete in Alex's name.

2 steps changed5 steps removedAgainst 1.1. Delegation vs. Impersonation SemanticsOAuth 2.0 Token Exchange rfc

The chain, step by step

AlexUser
Orchestrator agentAgent
auth.docs.exampleAuthorization server
Research sub-agentAgent
Documents APIResource
  1. Step 1: Alex to Orchestrator agent

    Write me a report from this quarter's documents

    The orchestrator already holds an access token for the documents API that Alex obtained through the usual authorization code flow.

    1.1. Delegation vs. Impersonation SemanticsOAuth 2.0 Token Exchange rfc

    Alex's access token held by the orchestratortyp at+jwt · alg ES256 · kid docs-2026

    iss
    https://auth.docs.example
    sub
    alex
    aud
    https://api.docs.example
    client_id
    orchestrator
    scope
    docs:read docs:write
    exp
    1790000000
    iat
    1789996400
    jti
    a1

    Unchanged since the previous token in this chain.

  2. Step 2: Orchestrator agent to auth.docs.exampleremoved by the toggle

    POST /token: grant_type=token-exchange, subject_token=<Alex's token>, actor_token=<orchestrator credential>, audience=https://api.docs.example, scope=docs:read

    Delegation, not impersonation: the orchestrator identifies itself with an actor token and asks for less than it holds.

    2.1. RequestOAuth 2.0 Token Exchange rfc

  3. Step 3: auth.docs.example to Orchestrator agentremoved by the toggle

    Delegated token: sub=alex, act.sub=orchestrator, scope=docs:read

    4.1. act (Actor) ClaimOAuth 2.0 Token Exchange rfc

  4. Step 4: Orchestrator agent to Research sub-agentreplaces "hand-over"

    Task plus Alex's token, unchanged

    1.1. Delegation vs. Impersonation SemanticsOAuth 2.0 Token Exchange rfc

    Alex's token, forwardedtyp at+jwt · alg ES256 · kid docs-2026

    iss
    https://auth.docs.example
    sub
    alex
    aud
    https://api.docs.example
    client_id
    orchestrator
    scope
    docs:read docs:write
    exp
    1790000000
    iat
    1789996400
    jti
    a1

    Unchanged since the previous token in this chain.

  5. Step 5: Research sub-agent to auth.docs.exampleremoved by the toggle

    POST /token: grant_type=token-exchange, subject_token=<delegated token>, actor_token=<sub-agent credential>, audience=https://api.docs.example, scope=docs:read

    2.1. RequestOAuth 2.0 Token Exchange rfc

  6. Step 6: auth.docs.example to itselfremoved by the toggle

    Check may_act on the subject token names the actor; keep scope within the subject token's

    The chain can only grow by parties the previous token authorised, and never wider.

    4.4. may_act (Authorized Actor) ClaimOAuth 2.0 Token Exchange rfc

  7. Step 7: auth.docs.example to Research sub-agentremoved by the toggle

    Delegated token with a nested act chain

    4.1. act (Actor) ClaimOAuth 2.0 Token Exchange rfc

  8. Step 8: Research sub-agent to Documents APIreplaces "api-call"

    GET /documents with Authorization: Bearer <Alex's token>

    Nothing in the token says a sub-agent is calling. The API's audit trail names Alex and the orchestrator's client id, and the scope allows writes the task never needed.

    1.1. Delegation vs. Impersonation SemanticsOAuth 2.0 Token Exchange rfc

    Alex's token as presented by the sub-agenttyp at+jwt · alg ES256 · kid docs-2026

    iss
    https://auth.docs.example
    sub
    alex
    aud
    https://api.docs.example
    client_id
    orchestrator
    scope
    docs:read docs:write
    exp
    1790000000
    iat
    1789996400
    jti
    a1

    Unchanged since the previous token in this chain.

  9. Step 9: Documents API to itself

    Validate signature, iss, aud and exp; enforce docs:read; log sub and the act chain

    The audit record says the sub-agent read documents for Alex by way of the orchestrator, and the API can refuse actors it does not expect.

    4.1. act (Actor) ClaimOAuth 2.0 Token Exchange rfc

  10. Step 10: Documents API to Research sub-agent

    200 with the documents

    4. Validating JWT Access TokensJSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens rfc

Requirements this chain exercises