From 1f96a47f2a0194decda52b430b700c0c033347a3 Mon Sep 17 00:00:00 2001 From: Dobbie Date: Thu, 12 Mar 2026 15:08:53 +0000 Subject: [PATCH] Address PR review feedback - Remove Authorization: Bearer extraction to avoid spurious rate-limit hits from unrelated OAuth/OIDC tokens forwarded by proxy - Add JSDoc documenting that header token feature requires dangerouslyDisableDeviceAuth: true (token not used as device candidate) --- .../server/ws-connection/auth-context.ts | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/gateway/server/ws-connection/auth-context.ts b/src/gateway/server/ws-connection/auth-context.ts index fd9e4969a8b..0a4ac195af5 100644 --- a/src/gateway/server/ws-connection/auth-context.ts +++ b/src/gateway/server/ws-connection/auth-context.ts @@ -52,22 +52,18 @@ function trimToUndefined(value: string | undefined): string | undefined { /** * Extract token from WebSocket upgrade request headers. - * This allows nginx proxy to inject X-OpenClaw-Token header for browser clients - * that cannot send custom WebSocket headers. + * This allows a trusted reverse proxy to inject X-OpenClaw-Token header + * for browser clients that cannot send custom WebSocket headers. + * + * Note: Only X-OpenClaw-Token is extracted, not Authorization: Bearer. + * The standard Authorization header may contain unrelated OAuth/OIDC tokens + * that would cause spurious rate-limit hits if treated as gateway auth. */ function extractHeaderToken(req: IncomingMessage): string | undefined { const headerToken = req.headers["x-openclaw-token"]; if (typeof headerToken === "string" && headerToken.trim()) { return headerToken.trim(); } - // Also check Authorization: Bearer header - const auth = req.headers.authorization; - if (typeof auth === "string" && auth.toLowerCase().startsWith("bearer ")) { - const token = auth.slice(7).trim(); - if (token) { - return token; - } - } return undefined; } @@ -104,6 +100,19 @@ function resolveBootstrapTokenCandidate( return trimToUndefined(connectAuth?.bootstrapToken); } +/** + * Resolve auth state for a WebSocket connect handshake. + * + * When the request comes from a trusted proxy (gateway.trustedProxies), + * extracts X-OpenClaw-Token header and uses it as shared auth. This enables + * browser clients behind a reverse proxy to authenticate without device pairing + * when gateway.controlUi.dangerouslyDisableDeviceAuth is enabled. + * + * Limitations: + * - Header token is only used as shared auth, not as device token candidate. + * Browser clients authing solely via header need dangerouslyDisableDeviceAuth: true + * or must pass primary auth (token/password) via authorizeWsControlUiGatewayConnect. + */ export async function resolveConnectAuthState(params: { resolvedAuth: ResolvedGatewayAuth; connectAuth: HandshakeConnectAuth | null | undefined;