Delegation chain explorer

An MCP client obtains a token for an MCP server

The baseline chain of MCP Authorization 2026-07-28: an agent host discovers where a tasks server's authorization server is, identifies itself with a client ID metadata document, runs the OAuth 2.1 code flow with PKCE and a resource indicator, and presents the token the server was issued for. The server validates it and uses a token of its own for the API behind it.

AttackMissing audience check

The MCP server validates the signature and expiry but not the audience. An attacker who obtained a token issued for a different resource behind the same authorization server presents it here, and the server accepts a token that was never meant for it.

2 steps changedAgainst Security Considerations › Token Audience Binding and ValidationMCP Authorization 2026-07-28

  • Defeats Audience validationMCP serverListed servers under MCP Authorization 2026-07-28: 0 supported, 0 partial, 0 unsupported, 34 unknown, 5 not applicable.

The chain, step by step

AlexUser
Agent hostMCP client
Tasks MCP serverMCP server
auth.tasks.exampleAuthorization server
Tasks APIResource
  1. Step 1: Agent host to Tasks MCP server

    POST /mcp (initialize) with no Authorization header

    The host has no token for this server yet, so it starts with the request any client makes first. Everything it learns about where to get a token comes from the answer.

    Authorization Server Discovery › Protected Resource Metadata Discovery RequirementsMCP Authorization 2026-07-28

  2. Step 2: Tasks MCP server to Agent host

    401 with WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp"

    The server must point at its protected resource metadata, either in this challenge or at the well-known location; this server does both.

    Authorization Server Discovery › Protected Resource Metadata Discovery RequirementsMCP Authorization 2026-07-28

  3. Step 3: Agent host to Tasks MCP server

    GET /.well-known/oauth-protected-resource/mcp

    3. Protected Resource MetadataOAuth 2.0 Protected Resource Metadata rfc

  4. Step 4: Tasks MCP server to Agent host

    resource: https://mcp.tasks.example/mcp, authorization_servers: [https://auth.tasks.example]

    The resource identifier is what the client will ask the token to be bound to; the authorization server list is where it will ask.

    Authorization Server Discovery › Authorization Server LocationMCP Authorization 2026-07-28

  5. Step 5: Agent host to auth.tasks.example

    GET /.well-known/oauth-authorization-server

    3. Obtaining Authorization Server MetadataOAuth 2.0 Authorization Server Metadata rfc

  6. Step 6: auth.tasks.example to Agent host

    issuer, endpoints, code_challenge_methods_supported: [S256], client_id_metadata_document_supported: true

    The issuer must match the URL the client asked; the client keeps the metadata keyed by that issuer.

    Authorization Server Discovery › Authorization Server Metadata DiscoveryMCP Authorization 2026-07-28

  7. Step 7: Agent host to auth.tasks.example

    Authorization request via Alex's browser: client_id=https://agent.example/client.json, code_challenge (S256), resource=https://mcp.tasks.example/mcp, state

    The client identifies itself with the URL of its metadata document instead of registering first. The resource parameter names the server the token is for.

    Client Registration › Client ID Metadata DocumentsMCP Authorization 2026-07-28

  8. Step 9: auth.tasks.example to Agent host

    Redirect with code, state and iss=https://auth.tasks.example

    The client compares iss byte for byte with the issuer it discovered before it uses the code; a mismatch means the response came from somewhere else.

    Authorization › Authorization Response ValidationMCP Authorization 2026-07-28

  9. Step 10: Agent host to auth.tasks.example

    POST /token: grant_type=authorization_code, code, code_verifier, resource=https://mcp.tasks.example/mcp

    Security Considerations › Authorization Code ProtectionMCP Authorization 2026-07-28

  10. Step 11: auth.tasks.example to Agent host

    Access token bound to the tasks server

    The authorization server verified the code verifier against the challenge and issued a token whose audience is the resource the client asked for.

    Security Considerations › Token Audience Binding and ValidationMCP Authorization 2026-07-28

    Access token for the Tasks MCP servertyp at+jwt · alg ES256 · kid auth-2026-1

    iss
    https://auth.tasks.example
    sub
    alex
    aud
    https://mcp.tasks.example/mcp
    client_id
    https://agent.example/client.json
    scope
    tasks:read tasks:write
    exp
    1790000000
    iat
    1789996400
    jti
    7f2c

    Unchanged since the previous token in this chain. Shown in the RFC 9068 JWT profile; an opaque token would carry the same binding on the server side.

  11. Step 12: Agent host to Tasks MCP serverreplaces "bearer-call"

    POST /mcp with Authorization: Bearer <a token issued for https://notes.example>

    The token is genuine and unexpired, signed by the same authorization server, but its audience is another resource.

    Security Considerations › Token Audience Binding and ValidationMCP Authorization 2026-07-28

    A token for another resource, replayedtyp at+jwt · alg ES256 · kid auth-2026-1

    iss
    https://auth.tasks.example
    sub
    alex
    audchanged
    https://notes.example/mcp
    client_idchanged
    https://other-agent.example/client.json
    scopechanged
    notes:read
    exp
    1790000000
    iat
    1789996400
    jtichanged
    c4d1

    4 claims differ from the previous token in this chain.

  12. Step 13: Tasks MCP server to itselfreplaces "validate"

    Validate signature, iss and exp only; aud is not compared

    Without the audience check every token the authorization server ever issued for any of its resources opens this server.

    Security Considerations › Token Audience Binding and ValidationMCP Authorization 2026-07-28

  13. Step 14: Tasks MCP server to Tasks API

    GET /tasks with a token the server obtained for the API (here by token exchange, acting for Alex)

    The server never forwards the token it received. It holds credentials of its own for the API and obtains a token whose audience is the API, so the API can tell who is calling on whose behalf.

    Security Considerations › Access Token Privilege RestrictionMCP Authorization 2026-07-28

    The server's own token for the Tasks APItyp at+jwt · alg ES256 · kid auth-2026-1

    iss
    https://auth.tasks.example
    sub
    alex
    audchanged
    https://api.tasks.example
    client_idchanged
    tasks-mcp-server
    scopechanged
    tasks:read
    actadded
    {
      "sub": "tasks-mcp-server"
    }
    expchanged
    1789999000
    iatchanged
    1789996500
    jtichanged
    9b10

    7 claims differ from the previous token in this chain.

  14. Step 15: Tasks MCP server to Agent host

    200 with the tool result

    Authorization › Access Token UsageMCP Authorization 2026-07-28

Requirements this chain exercises