fix(mcp): require audience-bound OAuth JWTs - #3130
Open
fahreddinozcan wants to merge 1 commit into
Open
Conversation
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.
Summary
Replace the permissive OAuth ingress behavior with locally verified, audience-bound JWT access tokens on
/mcp/oauth.This supersedes #3068. Server-side validation is still required for every bearer token; the change is that Clerk JWT access tokens can be verified locally from JWKS, while opaque values can only be trusted after authoritative introspection. Passing an opaque string through to the downstream API was not sufficient validation at the MCP resource boundary.
What changes
/mcp/oauth, including legacyoat_tokens, API keys, and arbitrary bearer strings.RESOURCE_URL);RS256allowlist;sub,iat, andexpclaims; andprofile emailscopes by default./mcpanonymous/API-key behavior unchanged.OAUTH_ACCESS_TOKEN_AUDIENCEandOAUTH_REQUIRED_SCOPESvalues.OAuth vs OIDC
This migrates OAuth access tokens to JWT format; it does not use OIDC ID tokens as API credentials. ID tokens describe the user's authentication event and are intended for the client. Requiring the MCP resource audience and delegated OAuth scopes prevents an otherwise similarly signed ID token from being accepted by the resource server.
Deployment gate
Before deployment, enable Generate access tokens as JWTs for the Clerk OAuth application in staging and inspect a token obtained through the complete authorization-code flow.
The token must include the configured issuer,
aud=https://mcp.context7.com,sub,iat,exp, and the required scopes. Although the callback currently forwards the RFC 8707resourceparameter, Clerk's public documentation does not guarantee that this value becomes the JWTaudclaim.If Clerk does not produce an MCP-bound audience, do not deploy and do not remove audience validation. Configure the audience in Clerk or introduce a Context7 token-exchange issuer instead. The full procedure is in
packages/mcp/OAUTH_JWT_MIGRATION.md.Existing opaque-token holders may need to re-authorize. JWT revocation is bounded by token expiry, so token lifetime is an operational security setting.
Test plan
pnpm --filter @upstash/context7-mcp format:checkpnpm --filter @upstash/context7-mcp typecheckpnpm --filter @upstash/context7-mcp lint:checkpnpm --filter @upstash/context7-mcp testResult: 6 test files and 63 tests passed.
New coverage asserts strict Clerk verification options, required scopes, and rejection of opaque, API-key-shaped, and arbitrary bearer credentials on
/mcp/oauth.Follow-up boundary
The MCP server currently forwards the authenticated bearer credential to the Context7 API. If those components are treated as separate resource servers, that hop should be replaced with a scoped internal assertion or service credential. This PR fixes ingress validation and documents that follow-up; it does not claim bearer-token forwarding is resolved.
References