Skip to content

MCP OAuth loopback flow sends full callback URL as state, breaks strict OAuth servers (e.g. Miro MCP) #52

Description

@chrissygiss

When connecting to an MCP server that requires OAuth (tested with Miro's MCP server, https://mcp.miro.com/), the authorization flow started by the Copilot language server's LoopbackAuthServer always fails with:

CopilotAuthError: Missing required parameters, at least one from code, state, nonce is needed.

Root cause (from logs)

The state parameter sent in the /authorize request is the entire local callback URL including its own query string (containing the nonce), instead of an opaque URL-safe token:

state=http://127.0.0.1:33428/callback?nonce=<redacted>

Miro's authorization server validates state strictly against A-Za-z0-9_-+=/.: % (no ? allowed) and rejects the request as invalid_request before it can redirect back with a code. The loopback server then reports the callback as missing required parameters, because the browser redirect it receives is Miro's error redirect, not a successful auth code.

Environment

  • Plugin: GitHub Copilot for JetBrains (github-copilot-intellij) version 1.18.0-261
  • IDE: PhpStorm 2026.1 (macOS)
  • MCP server: Miro (https://mcp.miro.com/)
  • Underlying language server: copilot-language-server-internal (see stack trace below)

Log excerpt (idea.log)

INFO - [LoopbackAuthServer] OAuth server started and state configured { port: 33428, redirectUri: 'http://127.0.0.1:33428/callback' }
INFO - [default] Auth URL created and opening browser for sign-in
INFO - [LoopbackAuthServer] Redirecting to auth server
WARN - [LoopbackAuthServer] OAuth callback missing required parameters {
  originalUrl: 'https://mcp.miro.com/authorize?client_id=<redacted>&response_type=code&scope=boards%3Aread+boards%3Awrite+email+openid&code_challenge=<redacted>&code_challenge_method=S256&resource=https%3A%2F%2Fmcp.miro.com%2F&state=http%3A%2F%2F127.0.0.1%3A33428%2Fcallback%3Fnonce%3Dbd5505e8c9683bed174cce861744ce5b&redirect_uri=http%3A%2F%2F127.0.0.1%3A33428%2Fcallback',
  callbackUrl: '/callback?error=invalid_request&error_description=Invalid+authorization+parameters%3A+state%3A+Value+error%2C+Invalid+state+format.+Must+be+1-2048+URL-safe+characters+%28A-Za-z0-9_-%2B%3D%2F.%3A%25%29&state=http%3A%2F%2F127.0.0.1%3A33428%2Fcallback%3Fnonce%3Dbd5505e8c9683bed174cce861744ce5b'
}
WARN - [default] OAuth flow error CopilotAuthError: Missing required parameters, at least one from code, state, nonce is needed.
    at Server.<anonymous> (/snapshot/copilot-language-server-internal/dist/main.js:4281:1582)
    at Server.emit (node:events:519:28)
    at parserOnIncoming (node:_http_server:1186:12)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:125:17)
WARN - [mcpGateway] Interactive OAuth failed for https://mcp.miro.com/ CopilotAuthError: Missing required parameters, at least one from code, state, nonce is needed.
WARN - [mcpGateway.manager] server 'miro' requires authorization

Steps to reproduce

  1. In PhpStorm, add an MCP server config for Miro: { "url": "https://mcp.miro.com/" }.
  2. Trigger the "Connect"/authorization flow for that server.
  3. Browser opens Miro's authorize page; it immediately redirects back with error=invalid_request instead of a code.
  4. Copilot reports "server 'miro' requires authorization" indefinitely — the flow can never succeed.

Expected behavior

The state parameter should be an opaque, URL-safe random token (e.g. just the nonce, or a base64url-encoded value), with the nonce/return-path tracked server-side in the loopback server's own session state — not encoded as a full URL with its own query string. This would satisfy strict OAuth servers like Miro's that validate state format per RFC recommendations.

Impact

Any MCP server that validates the state parameter format strictly (rejecting non-URL-safe characters like ?) cannot be authorized via the JetBrains Copilot plugin's built-in OAuth loopback flow. Confirmed with Miro's official MCP server.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions