MCP OAuth 2.1 ceremonial flow for claude.ai connector - #31
Merged
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
/authorizeauto-approves and tokens carrysub: "anonymous". Downstream code must not treatsubas a user identifier./mcp— requests WITHOUT an Authorization header still succeed unchanged. Only invalid/expired tokens are rejected. Existing production clients are not affected.node:cryptoinsrc/oauth/jwt.ts(~150 lines) and trivially swappable forjoselater if asymmetric keys are ever needed./register10/min,/authorize30/min,/token30/min — returns 429 +Retry-Afteron exceed.plain), timing-safe verifier comparison, redirect_uri validated at both/authorizeand/token, one-time-use codes with 10-minute TTL.Required pre-merge step
Set
MCP_JWT_SECRETon Railway copilotkit-docs service BEFORE merging. Generate with:Without this, production startup will fail with
MCP_JWT_SECRET is required in production. In development the secret is auto-generated at startup (ephemeral — all tokens invalidated on restart).New files
src/oauth/jwt.ts— HS256 sign/verify with base64url, clock-skew handling, typed error classessrc/oauth/store.ts— in-memoryclientStore+codeStoresingletons (lazy expiry at consume time)src/oauth/secret.ts—resolveJwtSecret({nodeEnv})with dev/prod policy + cachesrc/oauth/rate-limiter.ts—OAuthRateLimiterclass + three per-endpoint singletonssrc/oauth/handlers.ts— metadata, register, authorize, token handlers + opportunistic bearer middlewareModified files
src/server.ts— replaces the old stub OAuth endpoints with real handlers, mountsbearerMiddlewareon/mcpPOST/DELETE, addsexpress.urlencodedafterexpress.jsonsrc/config.ts— addsmcpJwtSecret: stringto theConfiginterface, resolves viaresolveJwtSecret({nodeEnv})inparseConfig().env.example— documentsMCP_JWT_SECRETmcpJwtSecretto satisfyConfigtypingTest plan
fetch; covers opportunistic-no-auth and garbage-token 401 pathsnpm test— 2364 passing / 2368 total (4 pre-existing failures inanalytics-server.test.ts— 2 unique tests × 2 becausetscemits tests intodist/; present onorigin/mainunchanged, unrelated to OAuth)npm run build— clean, zero TypeScript errorsnpx prettier --check "src/**/*.ts"— cleanas anytypecasting introducedcurl https://mcp.copilotkit.ai/.well-known/oauth-protected-resourcereturnsauthorization_serverscurl https://mcp.copilotkit.ai/.well-known/oauth-authorization-serverreturns full AS metadatacurl -X POST https://mcp.copilotkit.ai/register -H 'Content-Type: application/json' -d '{"redirect_uris":[]}'returns 201POST /mcpstill works (no regression)Observability
All OAuth events log with
[oauth]prefix. INFO on successful register/authorize/token (client_id, IP). WARN on PKCE failures, unknown clients, expired codes, and rate limits. Tokens and code verifiers are never logged.Security details
crypto.timingSafeEqual) on PKCE verification and JWT signature/authorizeand/token