Skip to content

feat: OAuth token and audience validation for A2A agents - #7510

Open
marekdano wants to merge 3 commits into
mainfrom
5815-a2a-oauth-audience-validation
Open

marekdano wants to merge 3 commits into
mainfrom
5815-a2a-oauth-audience-validation

Conversation

@marekdano

Copy link
Copy Markdown
Collaborator

Summary

Closes #5815.

An A2A agent with auth_type="oauth" stored oauth_config, but no code path used it. The gateway now gets an agent-level client_credentials token before it calls the agent. It validates the token before it forwards it.

Changes

  • Add mcpgateway/services/a2a_oauth.py. resolve_a2a_oauth_headers() requests the token, validates it, caches it, and returns the Authorization header.
  • Send the RFC 8707 resource on the token request. The value is oauth_config["resource"], else the origin of the agent endpoint (derive_resource_origin()).
  • Validate the token with validate_oauth_token_claims(). A mismatch of a configured audience, scopes, or issuer blocks the call. A mismatch of a derived audience is advisory unless OAUTH_REQUIRE_CONFIGURED_RESOURCE=true.
  • Cache the token per agent in the existing service-token cache. Only validated tokens enter the cache. The key covers the resource and the client credentials.
  • Add send_resource to OAuthManager.get_client_credentials_token_response(). The default is False, so gateway and discovery callers send the same request as before.
  • Add oauth_headers to prepare_a2a_invocation(). The gateway applies it only when auth_type="oauth".
  • Wire the token into A2AAgentService.invoke_agent and both A2A paths in ToolService.
  • Add the Resource (Audience) field to the A2A agent create and edit forms in the Admin UI. Stop passing include_resource=False in the two A2A admin handlers.
  • Document the A2A token lifecycle in oauth-resource-configuration.md.

Behavior

  • Only client_credentials is supported. Any other grant_type fails with an A2AAgentError that names the grant type.
  • Token request failures return a generic message. The IdP error detail stays in the logs.
  • The gateway never logs the token.
  • No schema, API, or environment variable change.

Decisions

  • The token lifecycle is agent-level. The per-user authorization_code flow with token storage and refresh is deferred by design. It needs an Alembic migration and goes in a separate issue.
  • The web UI needs no change. Its agent form already sends client_credentials.

  An A2A agent with auth_type="oauth" stored oauth_config but never used
  it. The gateway now gets an agent-level client_credentials token before
  it calls the agent.

  - Send the RFC 8707 resource on the token request. Use the configured
    value, else the origin of the agent endpoint.
  - Validate token audience, scopes, and issuer with
    validate_oauth_token_claims() before the gateway forwards the token.
    Apply the gateway precedence and OAUTH_REQUIRE_CONFIGURED_RESOURCE.
  - Cache the token per agent in the service-token cache. The key covers
    the resource and the client credentials.
  - Add send_resource to get_client_credentials_token_response(). It is
    off by default, so existing callers keep their request shape.
  - Wire the token into A2AAgentService.invoke_agent and both A2A paths
    in ToolService.

  Other grant types fail with an error. The per-user authorization_code
  flow and the Resource field on the A2A forms stay open under #5815.

Signed-off-by: Marek Dano <mk.dano@gmail.com>
  An A2A agent with auth_type="oauth" stored oauth_config but never used
  it. The gateway now gets an agent-level client_credentials token before
  it calls the agent.

  - Send the RFC 8707 resource on the token request. Use the configured
    value, else the origin of the agent endpoint.
  - Validate token audience, scopes, and issuer with
    validate_oauth_token_claims() before the gateway forwards the token.
    Apply the gateway precedence and OAUTH_REQUIRE_CONFIGURED_RESOURCE.
  - Cache the token per agent in the service-token cache. The key covers
    the resource and the client credentials.
  - Add send_resource to get_client_credentials_token_response(). It is
    off by default, so existing callers keep their request shape.
  - Wire the token into A2AAgentService.invoke_agent and both A2A paths
    in ToolService.
  - Add Resource (Audience) to the A2A agent create and edit forms. Stop
    passing include_resource=False in the A2A admin handlers.
  - Document the A2A token lifecycle.

  Other grant types fail with an error. The per-user authorization_code
  flow is not part of this change.

  Closes #5815

Signed-off-by: Marek Dano <mk.dano@gmail.com>
  The diff-coverage gate reported 89% against the 90% minimum. Add tests
  for the changed lines that no test reached.

  - Cover the cache hit that happens while a request waits for the token
    lock, and the fallback TTL for an invalid expires_in.
  - Cover A2AAgentService.invoke_agent for an OAuth agent: the token
    becomes the Authorization header, and a token failure becomes an
    A2AAgentError.
  - Cover the OAuth token lookup in ToolService.invoke_tool and
    _call_a2a_agent.

Signed-off-by: Marek Dano <mk.dano@gmail.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: A2A agent OAuth token forwarding should validate audience (RFC 8707 resource support)

1 participant