From badaf526bb6eb238995e4dff7407bcba5914ef97 Mon Sep 17 00:00:00 2001 From: iamlukethedev Date: Wed, 8 Apr 2026 17:35:21 -0500 Subject: [PATCH] fix(gateway): disable device auth for managed remote token flows. Use shared-token auth without browser device signatures for non-local OpenClaw connections that already have a configured gateway token, while preserving local OpenClaw device auth behavior. Made-with: Cursor --- src/lib/gateway/GatewayClient.ts | 17 ++++++++++++++++- tests/unit/useGatewayConnection.test.ts | 5 +++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lib/gateway/GatewayClient.ts b/src/lib/gateway/GatewayClient.ts index 06c186a..eb8b241 100644 --- a/src/lib/gateway/GatewayClient.ts +++ b/src/lib/gateway/GatewayClient.ts @@ -136,6 +136,17 @@ export const resolveGatewayClientName = ( : OPENCLAW_WEBCHAT_UI_CLIENT_ID; }; +export const resolveGatewayDisableDeviceAuth = ( + adapterType: StudioGatewayAdapterType, + gatewayUrl: string, + token: string +) => { + if (adapterType !== "openclaw") { + return true; + } + return !isLocalGatewayUrl(gatewayUrl) && token.trim().length > 0; +}; + export const resolveInitialGatewayAutoConnectDelayMs = ( adapterType: StudioGatewayAdapterType ): number => { @@ -953,7 +964,11 @@ export const useGatewayConnection = ( token, authScopeKey: gatewayUrl, clientName: resolveGatewayClientName(selectedAdapterType, gatewayUrl), - disableDeviceAuth: selectedAdapterType !== "openclaw", + disableDeviceAuth: resolveGatewayDisableDeviceAuth( + selectedAdapterType, + gatewayUrl, + token + ), }); lastError = null; break; diff --git a/tests/unit/useGatewayConnection.test.ts b/tests/unit/useGatewayConnection.test.ts index 354db7b..327b035 100644 --- a/tests/unit/useGatewayConnection.test.ts +++ b/tests/unit/useGatewayConnection.test.ts @@ -20,11 +20,13 @@ const setupAndImportHook = async (gatewayUrl: string | null) => { token: unknown; authScopeKey: unknown; clientName: unknown; + disableDeviceAuth: unknown; } = { url: null, token: null, authScopeKey: null, clientName: null, + disableDeviceAuth: null, }; vi.doMock("../../src/lib/gateway/openclaw/GatewayBrowserClient", () => { @@ -42,6 +44,7 @@ const setupAndImportHook = async (gatewayUrl: string | null) => { captured.token = "token" in opts ? opts.token : null; captured.authScopeKey = "authScopeKey" in opts ? opts.authScopeKey : null; captured.clientName = "clientName" in opts ? opts.clientName : null; + captured.disableDeviceAuth = "disableDeviceAuth" in opts ? opts.disableDeviceAuth : null; this.opts = { onHello: typeof opts.onHello === "function" ? (opts.onHello as (hello: unknown) => void) : undefined, onEvent: typeof opts.onEvent === "function" ? (opts.onEvent as (event: unknown) => void) : undefined, @@ -240,6 +243,7 @@ describe("useGatewayConnection", () => { }); expect(captured.authScopeKey).toBe("wss://pi5.myth-coho.ts.net"); expect(captured.clientName).toBe("webchat-ui"); + expect(captured.disableDeviceAuth).toBe(true); }); it("keeps_control_ui_identity_for_local_openclaw_connections", async () => { @@ -286,6 +290,7 @@ describe("useGatewayConnection", () => { }); expect(captured.authScopeKey).toBe("ws://localhost:18789"); expect(captured.clientName).toBe("openclaw-control-ui"); + expect(captured.disableDeviceAuth).toBe(false); }); it("does_not_auto_connect_without_a_last_known_good_state", async () => {