diff --git a/ui/src/ui/app-gateway.ts b/ui/src/ui/app-gateway.ts index 4aacd29c51f..340922baf16 100644 --- a/ui/src/ui/app-gateway.ts +++ b/ui/src/ui/app-gateway.ts @@ -170,6 +170,11 @@ export function connectGateway(host: GatewayHost) { return; } host.connected = false; + // Code 1008 = Policy Violation (auth failure) — show the gateway's reason directly + if (code === 1008) { + host.lastError = reason || "Authentication failed. Check your gateway token."; + return; + } // Code 1012 = Service Restart (expected during config saves, don't show as error) if (code !== 1012) { host.lastError = `disconnected (${code}): ${reason || "no reason"}`; diff --git a/ui/src/ui/gateway.ts b/ui/src/ui/gateway.ts index 39ef7ec1c8e..36abce4c863 100644 --- a/ui/src/ui/gateway.ts +++ b/ui/src/ui/gateway.ts @@ -109,6 +109,13 @@ export class GatewayBrowserClient { this.ws = null; this.flushPending(new Error(`gateway closed (${ev.code}): ${reason}`)); this.opts.onClose?.({ code: ev.code, reason }); + // 1008 = Policy Violation (gateway auth rejection). + // Don't auto-reconnect on auth failures — surface the login gate + // so the user can fix their token/password instead of looping. + if (ev.code === 1008) { + this.closed = true; + return; + } this.scheduleReconnect(); }); this.ws.addEventListener("error", () => {