Skip to content

A2A Gateway: JWT/Bearer authentication and end-to-end claims propagation#480

Merged
rockfordlhotka merged 2 commits into
mainfrom
feature/a2a-jwt-bearer-auth
Jun 16, 2026
Merged

A2A Gateway: JWT/Bearer authentication and end-to-end claims propagation#480
rockfordlhotka merged 2 commits into
mainfrom
feature/a2a-jwt-bearer-auth

Conversation

@rockfordlhotka

Copy link
Copy Markdown
Member

Closes #264.

Summary

Adds JWT/Bearer authentication as a second A2A HTTP gateway auth scheme (generic OIDC) alongside the existing X-Api-Key scheme, and wires end-to-end claims propagation so the agent can independently treat a caller's identity as verified (IsSelfAsserted: false) rather than trusting a bare Source string.

JWT/Bearer authentication (generic OIDC)

  • JwtAuthOptions (config POCO): Authority, Audience, RequireHttpsMetadata. Bearer is enabled only when Authority is set — API-key-only deployments are unaffected.
  • AddA2AJwtBearerAuthentication registers the standard Microsoft.AspNetCore.Authentication.JwtBearer handler (JWKS auto-discovery) and widens the default authorization policy so POST / accepts either API key or a valid Bearer token.

Agent card advertises both schemes

  • BuildAgentCard exposes apiKey always, plus bearer (HttpAuthSecurityScheme) and openId (OIDC discovery URL) when JWT is enabled. The two schemes are listed as separate SecurityRequirement entries so they are OR-ed (either satisfies), not AND-ed.

End-to-end claims propagation

  • New rb-auth-claims well-known header.
  • RockBotBridgeHandler extracts verified claims (sub, name, iss, scope) from Bearer principals and forwards them as a JSON envelope header; API-key callers get no header (stay name-based).
  • New ClaimsForwardingAgentIdentityVerifier (now the default IAgentIdentityVerifier): builds a non-self-asserted identity from forwarded claims (populating Issuer + Claims), falling back to NameBasedAgentIdentityVerifier when the header is absent.

Config + docs

  • Host Program.cs binds the Jwt section; appsettings.json sample block; design/a2a-gateway-auth.md documents the OIDC options and the propagation contract.

Design decisions (confirmed during planning)

  • Generic OIDC (configurable Authority/Audience) over a targeted provider.
  • Forward extracted claims (rb-auth-claims), not the raw token — the trust boundary is the gateway; RabbitMQ is internal. Agent-side token re-validation against JWKS is an explicit non-goal.
  • Composite/fallback verifier so API-key and JWT callers are both handled by a single registration.

Testing

  • AgentCardTests — card advertises apiKey only when JWT is off; apiKey + bearer + openId (as separate OR-ed requirements) when on.
  • RockBotBridgeHandlerTests — Bearer principal emits rb-auth-claims; API-key principal does not; unauthenticated returns null.
  • ClaimsForwardingAgentIdentityVerifierTests — claims present → verified/non-self-asserted; absent → name-based fallback; malformed/empty handled.
  • Full unit suite passes (0 failures).

Out of scope

🤖 Generated with Claude Code

rockfordlhotka and others added 2 commits June 15, 2026 21:55
Add JWT/Bearer authentication as a second gateway auth scheme (generic
OIDC via configurable Authority/Audience) alongside the existing X-Api-Key
scheme, and wire end-to-end claims propagation so the agent can mark caller
identity as verified rather than self-asserted.

- WellKnownHeaders: add rb-auth-claims for gateway-verified caller claims
- Gateway: AddA2AJwtBearerAuthentication + multi-scheme default policy
  (accepts API key OR Bearer); advertise bearer/openId on the agent card
  as separate (OR-ed) security requirements
- RockBotBridgeHandler: forward verified JWT claims (sub/name/iss/scope)
  as rb-auth-claims for Bearer callers; API-key callers stay name-based
- Agent: ClaimsForwardingAgentIdentityVerifier (new default) builds a
  non-self-asserted identity from forwarded claims, falling back to the
  name-based verifier when absent
- Host config + design/a2a-gateway-auth.md documenting OIDC options and
  the propagation contract
- Tests for the agent card, claims-header builder, and the verifier
- Bump version to 0.13.0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a real end-to-end test of JWT/Bearer auth and claims propagation, and fix
a 401-challenge regression surfaced by it.

- docker-compose.a2a-test: add an oidc-server-mock issuer (password grant, JWT
  access tokens) and configure the gateway with Jwt__Authority; pass OIDC token
  endpoint + creds to the test harness
- JwtAuthScenarios: card advertises bearer/openId; valid bearer token accepted;
  invalid token rejected (401); claims propagated — the agent records the JWT
  caller under its sub with IsSelfAsserted=false and the IdP issuer
- AgentTrustEntry: record verification provenance (Issuer, IsSelfAsserted) so
  trust decisions/audits can tell verified callers from self-asserted ones;
  RockBotTaskHandler populates it from the verified identity
- Gateway auth: replace the multi-scheme authorization policy with a forwarding
  policy scheme (Bearer when Authorization: Bearer present, else API key). A
  single scheme now authenticates/challenges per request, fixing a
  double-challenge that reset the connection on 401 (broke both the
  unauthenticated and invalid-token cases)

Validated via docker compose: 18/18 integration scenarios pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@rockfordlhotka rockfordlhotka merged commit 4045b68 into main Jun 16, 2026
2 checks passed
@rockfordlhotka rockfordlhotka deleted the feature/a2a-jwt-bearer-auth branch June 16, 2026 14:42
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.

A2A Gateway: JWT/Bearer authentication and end-to-end claims propagation

1 participant