From 12f66b9413a0dc18ae268e64756559eaac0e0901 Mon Sep 17 00:00:00 2001 From: Bikram Chatterjee Date: Fri, 10 Jul 2026 13:13:13 +0200 Subject: [PATCH] fix: route OAuth token exchange through proxy to bypass CORS When using Via Proxy connection mode, the browser-side token exchange POST to the OAuth token endpoint is CORS-blocked by corporate MCP gateways. Fix by: 1. OAuthCallback: pass createProxyFetch(config) as fetchFn to auth() when connectionType is "proxy", so the token exchange goes through the Node.js proxy instead of the browser. 2. useConnection: accept optional serverUrlOverride in connect() and use it for InspectorOAuthClientProvider, avoiding a React state timing race where sseUrl hasn't updated yet when connectMcpServer() is called from onOAuthConnect. 3. useConnection: remove authProvider from proxy transport options for SSE and Streamable HTTP. The token is injected manually via headers; having authProvider on a proxy-URL transport causes the SDK to do OAuth discovery against localhost:6277 on 401, triggering a bogus redirect to /authorize on the proxy. 4. App.tsx: pass connectionType and config to OAuthCallback, and forward serverUrl to connectMcpServer after OAuth callback. --- client/src/App.tsx | 8 ++++++-- client/src/components/OAuthCallback.tsx | 16 +++++++++++++++- client/src/lib/hooks/useConnection.ts | 12 ++++++++---- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index 7cf6d751a..0ddfedb6d 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -603,7 +603,7 @@ const App = () => { (serverUrl: string) => { setSseUrl(serverUrl); setIsAuthDebuggerVisible(false); - void connectMcpServer(); + void connectMcpServer(undefined, 0, serverUrl); }, [connectMcpServer], ); @@ -1350,7 +1350,11 @@ const App = () => { ); return ( Loading...}> - + ); } diff --git a/client/src/components/OAuthCallback.tsx b/client/src/components/OAuthCallback.tsx index ccfd6d928..6fc956677 100644 --- a/client/src/components/OAuthCallback.tsx +++ b/client/src/components/OAuthCallback.tsx @@ -7,12 +7,20 @@ import { generateOAuthErrorDescription, parseOAuthCallbackParams, } from "@/utils/oauthUtils.ts"; +import { createProxyFetch } from "@/lib/proxyFetch"; +import type { InspectorConfig } from "@/lib/configurationTypes"; interface OAuthCallbackProps { onConnect: (serverUrl: string) => void; + connectionType?: "direct" | "proxy"; + config?: InspectorConfig; } -const OAuthCallback = ({ onConnect }: OAuthCallbackProps) => { +const OAuthCallback = ({ + onConnect, + connectionType, + config, +}: OAuthCallbackProps) => { const { toast } = useToast(); const hasProcessedRef = useRef(false); @@ -46,9 +54,15 @@ const OAuthCallback = ({ onConnect }: OAuthCallbackProps) => { // Create an auth provider with the current server URL const serverAuthProvider = new InspectorOAuthClientProvider(serverUrl); + const fetchFn = + connectionType === "proxy" && config + ? createProxyFetch(config) + : undefined; + result = await auth(serverAuthProvider, { serverUrl, authorizationCode: params.code, + ...(fetchFn ? { fetchFn } : {}), }); } catch (error) { console.error("OAuth callback error:", error); diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index 9694b891f..b3668f1bc 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -444,7 +444,11 @@ export function useConnection({ } }; - const connect = async (_e?: unknown, retryCount: number = 0) => { + const connect = async ( + _e?: unknown, + retryCount: number = 0, + serverUrlOverride?: string, + ) => { const clientCapabilities = { capabilities: { sampling: {}, @@ -496,7 +500,9 @@ export function useConnection({ const headers: HeadersInit = {}; // Create an auth provider with the current server URL - const serverAuthProvider = new InspectorOAuthClientProvider(sseUrl); + const serverAuthProvider = new InspectorOAuthClientProvider( + serverUrlOverride ?? sseUrl, + ); // Use custom headers (migration is handled in App.tsx) let finalHeaders: CustomHeaders = customHeaders || []; @@ -694,7 +700,6 @@ export function useConnection({ ); } transportOptions = { - authProvider: serverAuthProvider, eventSourceInit: { fetch: ( url: string | URL | globalThis.Request, @@ -716,7 +721,6 @@ export function useConnection({ mcpProxyServerUrl = new URL(`${getMCPProxyAddress(config)}/mcp`); mcpProxyServerUrl.searchParams.append("url", sseUrl); transportOptions = { - authProvider: serverAuthProvider, eventSourceInit: { fetch: ( url: string | URL | globalThis.Request,