You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I've reviewed your pr, thanks, this is well built. PKCE S256 mandatory with no plain fallback, exact-match redirect URIs, single-use codes with timingSafeEqual on the verifier, refresh rotation with family revocation, all tokens hashed at rest. And it unlocks the one thing a static mcp_token can't: claude.ai and ChatGPT remote connectors. :) I was planning to build it myself at some point.
However, I found some things to fix first.
Blocking: the resource audience is derived from two different sources.
Authorization stores it from settings.baseUrl (${baseUrl}/api/mcp). Validation recomputes it from request headers in mcpAuthentication.js:
Two problems. Behind a proxy that doesn't set X-Forwarded-Proto, this yields http:// against a stored https:// and every MCP call 401s after a successful OAuth flow. And comparing a stored audience against a client-supplied Host header defeats the point of RFC 8707 binding. Please derive it from settings.baseUrl, same source as oauthUrls(). mcpHttpRoute.js already imports getSettings.
Also needed:
Renumber the migration to 35. 32.configured-adapters.js is already on master.
Rename the tables to mcp_oauth_*. Single mcp:read scope, hardcoded in validateAccessToken, resource always /api/mcp. Generic oauth_* names imply Fredy is a general authorization server, which it won't become. Cheap to change now while the migration is unapplied.
Move addContentTypeParser into an encapsulated plugin. registerMcpOAuthRoutes(fastify) gets the root instance, so the urlencoded parser applies app-wide, contrary to the comment above it. sameSite: 'lax' covers us today, but it removes a CSRF layer from every route.
On refresh-token reuse you revoke the family but not the live access tokens. oauth_access_tokens.revoked_at exists and is never set, so a stolen access token stays valid for up to an hour after detection.
no way to view or revoke a granted client, no cleanup of expired codes and tokens (session-cleanup-cron is the pattern), and unbounded unauthenticated DCR.
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
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
Validation
eslint .TEST_MODE=offline vitest run test/api/mcpOAuthRoute.test.jsThe full offline suite completed 1,035 tests but the runner exited nonzero because this environment exhausted Vitest fork workers.