Skip to content

Commit 6607254

Browse files
uli-will-codeclaude
andcommitted
fix(gateway): skip backend self-pairing for auth.mode=none on loopback
The cron rejection is actually in shouldSkipBackendSelfPairing, not evaluateMissingDeviceIdentity. When auth.mode=none, authMethod is "none" which matches neither token/password nor device-token, so the backend self-pairing skip never triggers. The cron client provides device identity, passes the device-identity gate, but then fails at the pairing step with "pairing required". Add usesNoAuth to the skip condition: when the gateway is explicitly configured with no auth, its own backend services on loopback should not require pairing. The isGatewayBackendClient + isLocalClient + !hasBrowserOriginHeader guards are sufficient. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b26e669 commit 6607254

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

src/gateway/server/ws-connection/handshake-auth-helpers.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,5 +124,28 @@ describe("handshake auth helpers", () => {
124124
authMethod: "token",
125125
}),
126126
).toBe(false);
127+
128+
// auth.mode=none: no shared secret or device token exists, but the gateway
129+
// backend client on loopback should still skip pairing.
130+
expect(
131+
shouldSkipBackendSelfPairing({
132+
connectParams,
133+
isLocalClient: true,
134+
hasBrowserOriginHeader: false,
135+
sharedAuthOk: false,
136+
authMethod: "none",
137+
}),
138+
).toBe(true);
139+
140+
// auth.mode=none but remote: must not skip.
141+
expect(
142+
shouldSkipBackendSelfPairing({
143+
connectParams,
144+
isLocalClient: false,
145+
hasBrowserOriginHeader: false,
146+
sharedAuthOk: false,
147+
authMethod: "none",
148+
}),
149+
).toBe(false);
127150
});
128151
});

src/gateway/server/ws-connection/handshake-auth-helpers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,19 @@ export function shouldSkipBackendSelfPairing(params: {
7575
}
7676
const usesSharedSecretAuth = params.authMethod === "token" || params.authMethod === "password";
7777
const usesDeviceTokenAuth = params.authMethod === "device-token";
78+
// auth.mode=none: the gateway is explicitly configured with no auth, so there
79+
// is no shared secret or device token to prove. Requiring pairing in this
80+
// configuration adds friction without security value — any client can already
81+
// connect without credentials. The isGatewayBackendClient + isLocalClient
82+
// guards are sufficient.
83+
const usesNoAuth = params.authMethod === "none";
7884
// `authMethod === "device-token"` only reaches this helper after the caller
7985
// has already accepted auth (`authOk === true`), so a separate
8086
// `deviceTokenAuthOk` flag would be redundant here.
8187
return (
8288
params.isLocalClient &&
8389
!params.hasBrowserOriginHeader &&
84-
((params.sharedAuthOk && usesSharedSecretAuth) || usesDeviceTokenAuth)
90+
((params.sharedAuthOk && usesSharedSecretAuth) || usesDeviceTokenAuth || usesNoAuth)
8591
);
8692
}
8793

0 commit comments

Comments
 (0)