feat: add configurable client ID for WebSocket connect frame

Add a clientId option that can be set via:
- VITE_CLIENT_ID env var at build time
- Advanced section in the login screen at runtime
- Stored in localStorage with other credentials

Defaults to 'webchat' for backward compatibility. Users can set it
to 'openclaw-control-ui' to use OpenClaw's dangerouslyDisableDeviceAuth
bypass without post-install patching.

Closes #11
This commit is contained in:
Nicolas Varrot
2026-02-23 14:41:15 +00:00
parent 6ed6a4eadf
commit e8fe3329f3
6 changed files with 84 additions and 14 deletions

View File

@@ -272,13 +272,13 @@ export function useGateway() {
}
}, []);
const setupClient = useCallback(async (wsUrl: string, token: string, authMode: AuthMode = 'token') => {
const setupClient = useCallback(async (wsUrl: string, token: string, authMode: AuthMode = 'token', clientId?: string) => {
// Tear down existing client
if (clientRef.current) {
clientRef.current.disconnect();
}
const client = new GatewayClient(wsUrl, token, authMode);
const client = new GatewayClient(wsUrl, token, authMode, clientId);
clientRef.current = client;
// Load device identity for signed connect handshake
@@ -296,7 +296,7 @@ export function useGateway() {
setConnectError(null);
setIsConnecting(false);
isConnectingRef.current = false;
storeCredentials(wsUrl, token, authMode);
storeCredentials(wsUrl, token, authMode, clientId);
loadSessions();
loadAgentIdentity();
loadHistory(activeSessionRef.current);
@@ -445,7 +445,7 @@ export function useGateway() {
const stored = getStoredCredentials();
if (stored) {
// Init on mount — setupClient sets state as part of establishing the connection
setupClient(stored.url, stored.token, stored.authMode || 'token');
setupClient(stored.url, stored.token, stored.authMode || 'token', stored.clientId);
} else {
setAuthenticated(false);
}
@@ -503,8 +503,8 @@ export function useGateway() {
loadHistory(key);
}, [loadHistory]);
const login = useCallback((url: string, token: string, authMode: AuthMode = 'token') => {
setupClient(url, token, authMode);
const login = useCallback((url: string, token: string, authMode: AuthMode = 'token', clientId?: string) => {
setupClient(url, token, authMode, clientId);
}, [setupClient]);
const deleteSession = useCallback(async (key: string) => {