diff --git a/client/src/lib/hooks/__tests__/useConnection.test.tsx b/client/src/lib/hooks/__tests__/useConnection.test.tsx index 4907a085b..4a3546547 100644 --- a/client/src/lib/hooks/__tests__/useConnection.test.tsx +++ b/client/src/lib/hooks/__tests__/useConnection.test.tsx @@ -1283,6 +1283,34 @@ describe("useConnection", () => { ); }); + test("omits x-custom-auth-headers in direct connections to avoid CORS issues", async () => { + const customHeaders: CustomHeaders = [ + { name: "X-Tenant-ID", value: "acme-inc", enabled: true }, + { name: "X-Environment", value: "staging", enabled: true }, + ]; + + const propsWithDirectConnection = { + ...defaultProps, + customHeaders, + connectionType: "direct" as const, + }; + + const { result } = renderHook(() => + useConnection(propsWithDirectConnection), + ); + + await act(async () => { + await result.current.connect(); + }); + + // In direct connection mode, x-custom-auth-headers should NOT be sent + // because it is a proxy implementation detail that breaks CORS (#1100) + const headers = mockSSETransport.options?.requestInit?.headers; + expect(headers).toHaveProperty("X-Tenant-ID", "acme-inc"); + expect(headers).toHaveProperty("X-Environment", "staging"); + expect(headers).not.toHaveProperty("x-custom-auth-headers"); + }); + test("uses OAuth token when no custom headers or legacy auth provided", async () => { const propsWithoutAuth = { ...defaultProps, diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index e14d1037f..85482c980 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -559,7 +559,9 @@ export function useConnection({ }); // Add custom header names as a special request header for server processing - if (customHeaderNames.length > 0) { + // Only add when using proxy connection — this is a proxy implementation detail + // that would break CORS on direct connections (see #1100) + if (customHeaderNames.length > 0 && connectionType !== "direct") { headers["x-custom-auth-headers"] = JSON.stringify(customHeaderNames); }