docs/web/dashboard.md
The Gateway dashboard is the browser Control UI served at / by default
(override with gateway.controlUi.basePath).
Quick open (local Gateway):
gateway.tls.enabled: true, use https://127.0.0.1:18789/ and
wss://127.0.0.1:18789 for the WebSocket endpoint.Key references:
Authentication is enforced at the WebSocket handshake via the configured gateway auth path:
connect.params.auth.tokenconnect.params.auth.passwordgateway.auth.allowTailscale: truegateway.auth.mode: "trusted-proxy"See gateway.auth in Gateway configuration.
Security note: the Control UI is an admin surface (chat, config, exec approvals). Do not expose it publicly. The UI keeps dashboard URL tokens in sessionStorage for the current browser tab session and selected gateway URL, and strips them from the URL after load. Prefer localhost, Tailscale Serve, or an SSH tunnel.
openclaw dashboard (copies link, opens browser if possible, shows SSH hint if headless).openclaw dashboard still prints the
clean URL and tells you to use the token from OPENCLAW_GATEWAY_TOKEN or
gateway.auth.token as the URL fragment key token; it does not print token
values in logs.http://127.0.0.1:18789/.gateway.tls.enabled: true, dashboard/status links use
https:// and Control UI WebSocket links use wss://.gateway.auth.token (or
OPENCLAW_GATEWAY_TOKEN); openclaw dashboard can pass it via URL fragment
for one-time bootstrap, and the Control UI keeps it in sessionStorage for the
current browser tab session and selected gateway URL instead of localStorage.gateway.auth.token is SecretRef-managed, openclaw dashboard
prints/copies/opens a non-tokenized URL by design. This avoids exposing
externally managed tokens in shell logs, clipboard history, or browser-launch
arguments.gateway.auth.token is configured as a SecretRef and is unresolved in your
current shell, openclaw dashboard still prints a non-tokenized URL plus
actionable auth setup guidance.gateway.auth.password (or
OPENCLAW_GATEWAY_PASSWORD). The dashboard does not persist passwords across
reloads.gateway.auth.allowTailscale: true, and a
non-loopback identity-aware reverse proxy can satisfy
gateway.auth.mode: "trusted-proxy". In those modes the dashboard does not
need a pasted shared secret for the WebSocket.gateway.auth.mode: "trusted-proxy", or an SSH tunnel. HTTP APIs still use
shared-secret auth unless you intentionally run private-ingress
gateway.auth.mode: "none" or trusted-proxy HTTP auth. See
Web surfaces.<a id="if-you-see-unauthorized-1008"></a>
openclaw status; remote: SSH tunnel ssh -N -L 18789:127.0.0.1:18789 user@host then open http://127.0.0.1:18789/).AUTH_TOKEN_MISMATCH, clients may do one trusted retry with a cached device token when the gateway returns retry hints. That cached-token retry reuses the token's cached approved scopes; explicit deviceToken / explicit scopes callers keep their requested scope set. If auth still fails after that retry, resolve token drift manually.deviceToken, then stored device token, then bootstrap token.{scope, ip} are serialized before the failed-auth limiter records them, so
the second concurrent bad retry can already show retry later.openclaw config get gateway.auth.tokengateway.auth.password or
OPENCLAW_GATEWAY_PASSWORDOPENCLAW_GATEWAY_TOKEN in this shell, then rerun openclaw dashboardopenclaw doctor --generate-gateway-token