Commit Graph
4 Commits
Author SHA1 Message Date
WeekendsuperHero be779fff08 fix(mcp): accept native-app redirect URIs during OAuth DCR (#3431)
* fix(mcp): accept native-app redirect URIs during OAuth DCR

Dynamic client registration only allowed https and loopback http, so
Cursor's cursor:// callback failed POST /register. One custom scheme
in a mixed list (cursor:// + localhost + https) rejected the whole
client. Accept RFC 8252 private-use schemes while still rejecting
javascript/data/file and non-loopback http.

PKCE and the consent screen remain in place. Loopback-only Cursor
registrations already worked; this unblocks the default mixed payload.

* fix(mcp): harden OAuth DCR redirect URI validation

Reject empty trailing fragments (URI.parse yields "") that present?
missed, and forbid tel/sms/intent handler schemes. Localize the
invalid-redirect error_description. Native app schemes (cursor://,
vscode://, reverse-domain) stay allowed.

* test(mcp): cover native DCR token exchange and documented URIs

Exchange the PKCE authorization code at /oauth/token in the native-app
flow. Lock hosting docs to Cursor's desktop, loopback, and web callbacks
and register each documented redirect URI.

* docs(mcp): add method comments for OAuth DCR helpers

CodeRabbit's docstring coverage check only counted comments on methods
touched by the diff. Document create and the redirect URI helpers.
2026-09-08 02:16:39 +02:00
AtlasandJuan José Mata 53a87a7645 fix(mcp): assign OAuth clients read_write scope (#2884)
* fix(mcp): assign OAuth clients read_write scope

* fix(mcp): default registered OAuth scope

---------

Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-08-04 23:10:39 +02:00
RealDiligentandCursor 17b8fe2409 fix: block unsafe OAuth redirect URIs in dynamic registration (#2638)
* fix: resolve insecure OAuth redirect URI registration

Reject unsafe redirect URIs during dynamic OAuth client registration so only HTTPS and loopback HTTP callbacks are accepted. This prevents token/code exfiltration through attacker-controlled redirect targets while preserving local native client flows.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: normalize IPv6 loopback hosts in OAuth redirect validation

Strip bracketed IPv6 hosts before comparing against LOOPBACK_HOSTS so
http://[::1] callbacks are accepted as intended.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-22 00:41:58 +02:00
Will Wilson 2075c8c41c feat(mcp): OAuth 2.1 auth for MCP — connect Claude.ai with your Sure login (#2234)
* feat(mcp): add OAuth well-known discovery endpoints (RFC 8414 + RFC 9728)

Serves /.well-known/oauth-protected-resource (RFC 9728) and
/.well-known/oauth-authorization-server (RFC 8414) so MCP clients
can auto-discover the authorization server. Both endpoints are
unauthenticated and respect APP_URL for reverse-proxy deployments.

* feat(mcp): add dynamic client registration endpoint (RFC 7591)

POST /register creates a public Doorkeeper::Application on demand so
MCP clients (e.g. Claude.ai) can self-register without manual setup.
Validates redirect_uris (including blank entries), falls back to
"MCP Client" name, returns no client_secret (public client, PKCE only).
Rate-limited to 10 registrations/min/IP via Rack::Attack.

* feat(mcp): authenticate via Doorkeeper OAuth2, keep MCP_API_TOKEN as fallback

MCP endpoint now accepts OAuth2 Bearer tokens issued by Doorkeeper.
Falls back to the existing MCP_API_TOKEN env-var flow so self-hosted
deployments are not broken. Requires MCP_OAUTH_ENABLED or MCP_API_TOKEN
to be set — the endpoint returns 503 otherwise.

- OauthBase concern provides APP_URL-aware configured_base_url (trailing
  slash stripped to prevent double-slash URLs)
- Bearer scheme parsed case-insensitively (RFC 7235)
- Only read_write scope accepted — read scope would allow mutating tools
  (CreateGoal, ImportBankStatement), so read-only tokens are rejected
- Deactivated users rejected even with a valid Doorkeeper token
- WWW-Authenticate header on 401 points to RFC 9728 resource metadata
- SHA-256 digest used for constant-time env-var comparison
- Rack::Attack throttle added for POST /register
- Routes wired: /.well-known/*, /register, use_doorkeeper

* fix(mcp): disable Turbo on OAuth consent form for external redirect URIs

Turbo was intercepting the authorization form POST and XHR-fetching
the redirect_uri (e.g. https://claude.ai/api/mcp/auth_callback),
which CORS blocks. Extend the existing turbo_disabled guard to cover
any redirect_uri that doesn't originate from the app itself.

* feat(mcp): add Settings::McpController with connected clients view

- Settings > MCP page (under Advanced) shows the MCP server URL with
  copy button and step-by-step instructions for connecting Claude.ai
- Lists active non-mobile OAuth tokens with app name and revoke action;
  mobile device tokens are excluded to prevent accidental disconnection
- Removes the MCP_OAUTH_ENABLED env-var gate — OAuth auth is always
  available since Doorkeeper handles consent; MCP_API_TOKEN remains
  as a self-hosted fallback

* fix(mcp): remove client_credentials from grant_types_supported metadata

Only authorization_code is supported by the registration endpoint.
Advertising client_credentials was misleading — a client that reads
the metadata and attempts that flow would get an application with the
wrong grant type.
2026-06-11 16:19:58 +02:00