DEP for Enterprise-Managed Authorization for MCP (Resource Authorization Server / RFC 7523 jwt-bearer)#4842
Open
loafoe wants to merge 2 commits into
Open
DEP for Enterprise-Managed Authorization for MCP (Resource Authorization Server / RFC 7523 jwt-bearer)#4842loafoe wants to merge 2 commits into
loafoe wants to merge 2 commits into
Conversation
…ion Server role) Proposes the Resource Authorization Server side of the MCP EMA flow: accepting an ID-JAG via the JWT Bearer grant (RFC 7523) and issuing a resource-bound access token. Complements DEP 4600 (ID-JAG issuance). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Andy Lo-A-Foe <andy.loafoe@gmail.com>
5dbe07e to
c1fa430
Compare
Dex silently dropped the OAuth 2.0 "resource" parameter and always bound an access token's audience to the client_id, so MCP clients (and any RFC 8707 client) could not obtain a resource-restricted access token. This surfaced while building out the EMA Resource Authorization Server role: the audience binding is the linchpin of the EMA flow. Bind the access token's audience to the requested resource(s) when present, while keeping the ID token's aud equal to the client_id (OIDC Core). The two tokens diverge: access-token aud = resource, azp = client_id. - Add parseResourceParams with RFC 8707 §2 validation (absolute URI, no fragment); invalid values return the invalid_target error code. - Thread Resource []string through AuthRequest, AuthCode, RefreshToken and DeviceRequest across all storage backends (ent schemas + regenerated code, Kubernetes types, in-memory). Ent auto-migration adds the columns. - Honor resource in the authorization-code, refresh, and device-code flows. Other flows pass nil and are unchanged. - getAudience and cross-client scopes are untouched; with no resource the issued tokens are byte-for-byte identical to before (regression test). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
This branch covers the Resource Authorization Server role of the MCP Enterprise-Managed Authorization (EMA) extension, and has grown to include a foundational piece that role depends on: RFC 8707 Resource Indicators.
It now contains two related parts:
resourceparameter and bind access-token audiences to it. This is the linchpin the EMA flow relies on, and was previously a Future Improvement in the DEP.Part 1 — DEP: EMA Resource Authorization Server (RFC 7523 jwt-bearer)
Complement to DEP #4600 (ID-JAG issuance, PR #4611), whose description explicitly scopes out "Phase 2 (accepting ID-JAG as upstream identity via RFC 7523)". This DEP specifies exactly that phase, so Dex can sit in front of MCP servers as the authorization server in an enterprise-managed deployment.
Key points:
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearerat the existing/tokenendpointoauth-id-jag+jwttyp, issuer, audience per EMA §4, expiry, optionalclient_idallow-list)resourceclaim (EMA §5.1)authorization_grant_profiles_supportedadvertising theurn:ietf:params:oauth:grant-profile:id-jagprofile (EMA §6)oauth2.enterpriseManagedAuthorizationconfig block. No behavior change for existing deployments.Part 2 — RFC 8707 Resource Indicators (implementation)
Dex previously dropped the OAuth 2.0
resourceparameter silently and always set a token'saudto theclient_id. RFC 8707 clients — including MCP clients using Dynamic Client Registration — could therefore never obtain a resource-restricted access token. Since EMA's whole point is binding the audience to the MCP server, this had to be addressed directly.The subtlety: in Dex the access token is a signed JWT produced by the same builder as the ID token. OIDC Core requires the ID token's
audto be the client, while RFC 8707 wants the access token'saudto be the resource. So the two now diverge when aresourceis requested:aud= requested resource(s),azp= client_idaud= client_id (unchanged, OIDC-valid)What's included:
parseResourceParamswith RFC 8707 §2 validation (absolute URI, no fragment); invalid values return theinvalid_targeterror code.Resource []stringthreaded throughAuthRequest,AuthCode,RefreshToken, andDeviceRequestacross all storage backends (ent schemas + regenerated code, Kubernetes types, in-memory). Ent auto-migration adds the columns.resourcehonored in the authorization-code, refresh, and device-code flows. Other flows passniland are unchanged.getAudienceand cross-client scopes untouched. With noresource, issued tokens are byte-for-byte identical to before — covered by a regression test.parseResourceParams(valid / multiple / relative / non-URI / fragment), access-token-vs-ID-token audience divergence, multiple resources, the no-resource regression guard, and two cases inTestParseAuthorizationRequest. Full suite green across sqlite, postgres, etcd, kubernetes, and memory backends.No IANA-registered discovery flag exists for RFC 8707, so no discovery metadata change is made; Dex simply honors
resourcewhen sent. (The MCP-relevant advertisement is RFC 9728 protected-resource metadata, tracked separately.)Special notes for your reviewer
This PR has grown beyond the original docs-only DEP — Part 2 is a real, tested code change. The DEP (Part 1) builds on and assumes DEP #4600 / PR #4611; its reference implementation will follow as separate code. Part 2 (RFC 8707) stands on its own and is independently reviewable/mergeable.
Does this PR introduce a user-facing change?