anthropics / anthropics/claude-ai-mcp
OAuth loopback callback rejected for federated IdPs (Referer host ≠ IdP host) — regression in 1.21459.0
- Dominant language
- No language data
- Stars
- 471
- Forks
- 76
- PR merge metrics
- No merged PRs in 30d
Description
### MCP server URL or name
`https://mcp.example.com/mcp` (a managed connector; its OAuth authorization server is **Google-federated** — user signs in at `accounts.google.com`. Hostname redacted.)
### How are you connecting to this server?
Managed/enterprise deployment via `managedMcpServers` with `oauth: { clientId, callbackHost: 127.0.0.1, callbackPort: 3120 }`, connected through the direct MCP host (`custom3p-mcp` / `directMcpHost`). `inferenceProvider: gateway`.
### Where does the issue occur?
Claude Desktop **1.21459.0** on macOS 15.6 (Darwin 24.6.0). Interactive OAuth (Connect button).
### When did you last reproduce this?
2026-07-15
### Browser and OS
Claude Desktop 1.21459.0 (Electron), macOS 15.6 / Darwin 24.6.0
### Describe the issue
After updating to **1.21459.0**, interactive OAuth re-authorization fails for any managed MCP connector whose sign-in is **federated to a different host** (e.g. an IdP that redirects through Google/Okta/Azure AD). The browser opens, the user completes sign-in, but the app **rejects the loopback callback** because the callback's `Referer` host is the upstream federation IdP (`accounts.google.com`) rather than the connector's own IdP host (`mcp.example.com`). The flow can never complete, so the connector cannot be (re)connected.
This connector authorized and refreshed successfully for months prior to this build; the failure is new after updating. Existing cached tokens masked it until the connector was disconnected, forcing a fresh interactive auth.
**Control (same build, self-contained IdPs succeed):** on the identical build/session, connectors whose login is on their own domain authorize fine — Intercom (`mcp.intercom.com`) and Slack (`slack.com`) both open the browser, save tokens, and connect. The only difference is federation: their final redirect is on their own host so `Referer` matches the IdP; the federated connector's final redirect comes from `accounts.google.com`.
### Error details
`~/Library/Logs/Claude/main.log`, repeated on every retry:
```
[custom3p-mcp] opening authorize URL { server: 'Knowledge Base', host: 'mcp.example.com', state: '…' }
[custom3p-mcp] waiting for OAuth callback (browser opened) { server: 'Knowledge Base' }
[custom3p-mcp] rejecting loopback callback: Referer host "accounts.google.com" != IdP "mcp.example.com" (Origin absent)
```
Successful control on the same build:
```
[custom3p-mcp] opening authorize URL { server: 'Intercom', host: 'mcp.intercom.com', … }
[custom3p-mcp] saved OAuth tokens { server: 'Intercom', hasRefresh: true }
[custom3p-mcp] server connected { name: 'Intercom', toolCount: 13 }
```
### Expected behavior
The loopback callback is accepted and tokens are saved (as before 1.21459.0). Callback authenticity should be bound to the CSRF `state` parameter, not to the `Referer`/`Origin` host — which is unreliable across federated redirects and is intentionally stripped by some IdPs' `Referrer-Policy`.
### Additional context
**Root cause hypothesis:** 1.21459.0 appears to have added a loopback-callback check requiring `Referer` host == connector IdP host. This assumption breaks for any federated login, where the last page before the `127.0.0.1` redirect is the upstream identity provider. `Origin` is absent on the redirect, so the check falls back to `Referer` and hard-rejects.
**Impact:** any managed OAuth connector using federated sign-in (corporate SSO via Google/Okta/Azure AD) becomes impossible to (re)authorize after the update.
**Suggested fix:** validate the callback on `state`; when `Referer`/`Origin` are absent or cross-origin, allow the callback if `state` matches rather than rejecting.
**Workarounds:** server-side only, if you control the IdP (make the final loopback redirect originate from the connector's own host, or set `Referrer-Policy: no-referrer` on the redirecting hop). Not possible for third-party IdPs. No client-side or managed-config workaround (no version-pin key; `disableAutoUpdates` only freezes the already-updated build).
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.