Skip to content

feat(oauth): accept Cursor's exact MCP callback as a redirect URI - #53

Merged
frahlg-agents[bot] merged 1 commit into
mainfrom
oauth-cursor-redirect
Oct 26, 2026
Merged

frahlg-agents[bot] merged 1 commit into
mainfrom
oauth-cursor-redirect

Conversation

@frahlg-agents

@frahlg-agents frahlg-agents Bot commented Oct 26, 2026

Copy link
Copy Markdown
Contributor

Lets Cursor (and Grok Bot through Cursor) finish an MCP sign-in against FTW Cloud.

Change

  • checkRedirect accepts exactly cursor://anysphere.cursor-mcp/oauth/callback, byte for byte, and no other custom scheme. The https and http-loopback rules are unchanged.
  • DCR (/oauth/register) and CIMD both go through checkRedirect. /authorize still requires an exact match against the client's registered redirect_uris, since the loopback port leniency only applies to http. PKCE S256 is still required for every client, and /token still binds the redirect URI.
  • The consent page shows cursor://anysphere.cursor-mcp with the existing warning "That is a program on this computer. Approve only if you started it." The request view sets redirect.local=true.
  • The unverified-client error page's back link is now template.URL. It is built only from a redirect that checkRedirect accepted, with parameters encoded via url.Values. Without this, html/template blanked the cursor: link to #ZgotmplZ.

Tests (internal/oauth/cursor_redirect_test.go)

  • Exact URI accepted. 36 variants rejected: trailing slash, query, ?, #, fragment, other paths, a port, userinfo, other hosts, cursor://evil, cursor: opaque, uppercase scheme/host/path, percent-encoding, whitespace, NUL, cursor-insiders:, vscode:, javascript:, data:, file:, http:.
  • DCR registers it, and rejects variants or a mix with another custom scheme.
  • /authorize refuses variants and another client's use of it, with no Location. It refuses plain or missing PKCE, and the error link back to Cursor works.
  • The consent page shows the warning. The full flow returns code, state and iss to the exact callback. /token refuses another redirect_uri and a wrong verifier, and accepts the right one.
  • go vet, go test -race ./... and -tags ftwclouddev pass locally.

Security review (independent, two rounds)

  • Round 1 must-fix: any DCR client can register the URI, so a local app that claims cursor: could start its own flow. Declined: any DCR/CIMD client can already register http://127.0.0.1 or localhost with any port, so a malicious local program has that capability today. Cursor uses DCR without a CIMD document, so binding the URI to a verified client_id would break it. The defence is the owner approving on the box with the agent key, plus the local-program warning, PKCE S256, and exact redirect binding.
  • Round 1 should-fix: the consent UI made anysphere.cursor-mcp look like a web host. Fixed as described above.
  • Round 2: clean.

checkRedirect now accepts cursor://anysphere.cursor-mcp/oauth/callback, byte for byte, and no other custom scheme. DCR and CIMD both go through it; /authorize still needs an exact match against the client's registered redirect_uris, PKCE S256 stays required, and /token still binds the redirect URI.

The consent page shows it as cursor://anysphere.cursor-mcp with the local-program warning, and the request view marks it local. The error page's back link is typed template.URL, built only from a checked redirect, so html/template no longer blanks the cursor: link.
@frahlg-agents
frahlg-agents Bot merged commit 931e64b into main Oct 26, 2026
2 checks passed
@frahlg-agents
frahlg-agents Bot deleted the oauth-cursor-redirect branch October 26, 2026 13:17
frahlg-agents Bot added a commit to srcfl/ftw-plugin that referenced this pull request Oct 26, 2026
srcfl/ftw-cloud#53 is deployed: the exact cursor://anysphere.cursor-mcp/oauth/callback is accepted, other custom schemes are still refused.
frahlg-agents Bot added a commit to srcfl/ftw-plugin that referenced this pull request Oct 26, 2026
srcfl/ftw-cloud#53 is deployed: the exact cursor://anysphere.cursor-mcp/oauth/callback is accepted, other custom schemes are still refused.

Co-authored-by: frahlg-agents[bot] <343333642+frahlg-agents[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants