←All concepts

learntutorialcore5 minsince 2.4.0

oauthrfc-8707rfc-9728audienceidentityauth

Bind MCP tokens to one server (RFC 8707 audience binding)

Updated October 13, 2026

The problem

One identity provider usually issues tokens for many services. If an MCP server accepts any valid token from that issuer, a token a user handed to one MCP server can be replayed against another. RFC 8707 resource indicators fix this by naming the server a token is for; the server then has to refuse tokens that name someone else.

The deny

Hangar with resource_uri: https://hangar.example.com, two tokens from the same issuer and key, one minted for Hangar and one for another MCP server (mcp-hangar 2.27.2):

$ curl -s localhost:8000/.well-known/oauth-protected-resource
{"resource":"https://hangar.example.com","authorization_servers":["https://auth.example.com"]}

# aud = https://hangar.example.com
{"mcp_servers":[]}                                              [200]

# aud = https://other-mcp.example.com
{"error":"authentication_failed","message":"Invalid JWT audience",
 "details":{"auth_method":"jwt"}}                               [401]
www-authenticate: Bearer resource_metadata="https://hangar.example.com/.well-known/oauth-protected-resource"

Captured on a laptop against a local test issuer, whose address is shown here as auth.example.com. The first response is the RFC 9728 protected-resource metadata a client reads to learn which resource to ask the authorization server for.

The config that does it

auth:
  enabled: true
  oidc:
    enabled: true
    issuer: https://auth.example.com
    jwks_uri: https://auth.example.com/.well-known/jwks.json
    resource_uri: https://hangar.example.com

With resource_uri set, it is the audience every trusted issuer’s tokens must carry, and it is what the metadata advertises. For several tenants on one gateway, strict_tenant_audience with a tenant_audiences map requires a token’s audience to match the one mapped to its tenant, so a token minted for one tenant is refused as another.

What it does not do

  • It binds tokens to the gateway, not to each upstream. Hangar checks the token it receives. It does not forward that token to the MCP servers behind it; their credentials are set per server in Hangar’s config.
  • A valid token is not permission. Audience binding decides whether the token is for this gateway; roles decide what its holder may do. A token with the right audience and no matching role gets 403.
  • It does not mint tokens. Your authorization server has to support resource indicators and put the requested resource in aud.