agentic-community / agentic-community/mcp-gateway-registry
[Phase 5] ID-JAG (RFC 8693 token exchange) receiver on token proxy
- Vorherrschende Sprache
- Python
- Sterne
- 911
- Forks
- 234
- Ø Merge
- 1 T. 11 Std.
- Gemergte PRs (30 T.)
- 62
Beschreibung
# Sub-issue D: Implement ID-JAG (RFC 8693 token exchange) receiver on the token proxy
**Parent:** #988
**Labels:** `enhancement`, `oauth`, `mcp-spec`, `authentication`, `entra-id`, `subtask`
**Phase:** 5
**Depends on:** A, E
**Blocks:** none
---
## Summary
Add support for `grant_type=urn:ietf:params:oauth:grant-type:token-exchange` ([RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693)) on the Registry's `/oauth/token` endpoint so enterprise-SSO coding assistants can exchange a corporate ID token (via the IdP-issued **ID-JAG** — Identity Assertion Authorization Grant) for a short-lived Registry-scoped access token, with no user-visible browser redirect.
Applies to Domain A only. Domain B backends make their own choice.
## Background
The November 2025 MCP authorization spec direction ([Aaron Parecki](https://aaronparecki.com/2025/11/25/1/mcp-authorization-spec-update)) introduces ID-JAG as the enterprise-SSO story. Flow:
1. User signs into the coding assistant via corporate SSO (Entra, Okta, etc.).
2. The coding assistant asks the enterprise IdP to exchange the user's ID token for an ID-JAG token targeted at the Registry. IdP applies enterprise policy here: "is this user's group allowed to use Claude against the Registry?"
3. The assistant presents the ID-JAG token to the Registry's `/oauth/token` with `grant_type=token-exchange`.
4. Registry validates the ID-JAG (signature, issuer, audience, resource) and issues a Registry-scoped access token.
Why it matters: large-enterprise deployments with strict corporate SSO policies cannot tolerate the browser-redirect PKCE flow for every user / device. ID-JAG lets those environments gate Registry access on their IdP's policy engine while keeping the sign-in silent.
## Scope
### In scope
- **`POST /oauth/token`** accepts:
- `grant_type=urn:ietf:params:oauth:grant-type:token-exchange`
- `subject_token` (required): the ID-JAG token (a JWT).
- `subject_token_type=urn:ietf:params:oauth:token-type:jwt` (required).
- `resource` (required): canonical URI of the MCP server the assistant wants to call.
- `scope` (optional): space-separated scopes, subset of Registry `scopes_supported`.
- `audience` (optional).
- `requested_token_type=urn:ietf:params:oauth:token-type:access_token` (default).
- **Validation chain for the subject token**:
- Signature via JWKS of a configured trusted issuer. Issuer list is an allowlist, per-deployment config.
- `iss` claim in the issuer allowlist.
- `aud` claim includes the Registry's canonical URI.
- `exp` / `nbf` / `iat` sanity.
- `act` / `may_act` claims if present, logged for audit.
- Resource claim (whatever field the ID-JAG spec lands on) matches `resource` request parameter.
- **Response**: same shape as any `/oauth/token` response: `access_token`, `token_type: Bearer`, `expires_in`, optionally `refresh_token` (usually not — ID-JAG exchanges are typically short-lived and re-issued on demand).
- **Issuance**: access token issued by the same token-minting path as the authorization-code flow (sub-issue E). Audience is the requested `resource`; scopes are the intersection of requested, subject-token-carried, and Registry-supported.
- **No refresh_token issued** by default for token-exchange grants. Operators can opt in via config if they have a reason.
- **Caching / replay protection**: dedupe on subject token `jti` within a reasonable window to prevent replay. Cache `jti` + `exp` in a short-lived store.
- **Observability**: structured log line for every exchange (subject issuer, resource, scopes granted vs. requested, outcome). Metric for exchange outcome per issuer.
- **Docs page** in [docs/](docs/) explaining how to wire an enterprise IdP to issue ID-JAG tokens and how to configure the Registry's issuer allowlist.
- **Tests**:
- Unit: each validation failure (bad sig, wrong issuer, wrong audience, expired, missing resource, scope over-request, replay).
- Integration: fake enterprise IdP that signs ID-JAG tokens; Registry accepts and issues a Registry access token; token is then accepted by the AI Registry Tools path (S2 from the recommendation doc).
### Out of scope
- Publishing our own `issued_token_type` for outbound exchanges (we're a receiver, not an originator).
- Domain B support — explicitly Domain A only.
- CIMD publisher / consumer (handled in sub-issues B/C).
## Design notes
- ID-JAG validation shares 80% of its code path with the PKCE authorization-code flow's token-minting step. Refactor minting to take a "validated claims" input so both callers use the same issuer.
- Issuer allowlist lives alongside the existing provider config ([auth_server/providers/](auth_server/providers/)) but is its own concept — the issuer of the subject token may not be the same IdP that serves the Registry's web-UI login.
- Body size cap on `/oauth/token` requests; ID-JAG JWTs can be large.
- PII in ID-JAG tokens: do not log full token bodies. Log only `iss`, `sub` (hashed or partial), `aud`, `resource`.
## Acceptance criteria
- [ ] `POST /oauth/token` with `grant_type=urn:ietf:params:oauth:grant-type:token-exchange` returns a valid Registry access token when all validations pass.
- [ ] All documented failure modes return RFC-7591-style error responses with correct `error` codes (`invalid_grant`, `invalid_request`, `invalid_target`, `unauthorized_client`).
- [ ] Subject-token JWKS fetch cached per issuer with key rotation support.
- [ ] Replay protection on subject-token `jti`.
- [ ] Scope intersection: granted scopes ⊆ requested ∩ subject-token-authorized ∩ Registry-supported.
- [ ] No `refresh_token` issued by default.
- [ ] Audit log line per exchange, PII-safe.
- [ ] Unit tests for each failure branch.
- [ ] Integration test: fake enterprise IdP signs an ID-JAG, Registry exchanges for access token, access token successfully calls AI Registry Tools.
- [ ] Docs page in [docs/](docs/) on operator setup (Entra/Okta side) and Registry config.
## Risks and open questions
- **Spec maturity.** ID-JAG terminology (exact claim names, `issued_token_type`, `subject_token_type`) may still shift. Land this behind a feature flag; keep an eye on the MCP spec update.
- **Issuer trust model.** Multiple enterprise customers each wanting their own IdP allowlisted means the config surface grows. Have a plan for ECS / Helm config of the allowlist; tie to #896 where applicable.
- **Session revocation semantics.** If the enterprise IdP revokes the user, the ID-JAG token already issued remains valid until `exp`. Short lifetimes are the mitigation. Document clearly for operators.
## References
- [RFC 8693 Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693)
- [Aaron Parecki, MCP Authorization Spec Update (2025-11-25)](https://aaronparecki.com/2025/11/25/1/mcp-authorization-spec-update)
- Related umbrella: #256
- Recommendation doc §6 Phase 5 + §7 ID-JAG variant: [.scratchpad/coding-assistant-oauth/recommendation-2026-05-04.md](.scratchpad/coding-assistant-oauth/recommendation-2026-05-04.md)
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.