openclaw - 💡(How to fix) Fix Local backend services have no client class that auths via gateway token without device pairing AND retains operator scopes [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#63344Fetched 2026-04-09 07:55:04
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

When gateway.controlUi.allowInsecureAuth=false (the secure default), there is no client.id/mode combination a local backend service can use to:

  1. Pass the WS handshake on ws://127.0.0.1:18789 (loopback, no HTTPS), AND
  2. Retain operator.write scope so it can call messages/send,

while authenticating only with the gateway token (gateway.auth.token).

This forces local-loopback single-user setups to either (a) leave allowInsecureAuth=true (which raises a security audit warning) or (b) implement the full device-pairing protocol just to talk to the gateway from another local process on the same host.

Root Cause

The intent of allowInsecureAuth=false is to prevent Control UI sessions from being authenticated over an insecure transport — a legitimate concern for reverse-proxied or remote setups. But on a single-user, loopback-only host with no reverse proxy and no remote access, the flag's security benefit approaches zero while its cost is that essentially every local backend integration that wants to use the gateway WS API breaks.

Fix Action

Fix / Workaround

Workaround in use

Code Example

{
  type: "req", id: "...", method: "connect",
  params: {
    minProtocol: 3, maxProtocol: 3,
    client: { id: "openclaw-tui", mode: "ui", /* ... */ },
    role: "operator",
    scopes: ["operator.write", "operator.read"],
    auth: { token: GATEWAY_TOKEN }
  }
}

---

ws closed before connect ... reason=control ui requires device identity
(use HTTPS or localhost secure context)
RAW_BUFFERClick to expand / collapse

Summary

When gateway.controlUi.allowInsecureAuth=false (the secure default), there is no client.id/mode combination a local backend service can use to:

  1. Pass the WS handshake on ws://127.0.0.1:18789 (loopback, no HTTPS), AND
  2. Retain operator.write scope so it can call messages/send,

while authenticating only with the gateway token (gateway.auth.token).

This forces local-loopback single-user setups to either (a) leave allowInsecureAuth=true (which raises a security audit warning) or (b) implement the full device-pairing protocol just to talk to the gateway from another local process on the same host.

Environment

  • OpenClaw 2026.3.x
  • Gateway: bind=loopback, auth.mode=token, controlUi.allowInsecureAuth=false
  • Local service connects via ws://127.0.0.1:18789 from the same host as the gateway

Repro

A small Node WebSocket client connects to the gateway with the connect frame:

{
  type: "req", id: "...", method: "connect",
  params: {
    minProtocol: 3, maxProtocol: 3,
    client: { id: "openclaw-tui", mode: "ui", /* ... */ },
    role: "operator",
    scopes: ["operator.write", "operator.read"],
    auth: { token: GATEWAY_TOKEN }
  }
}

With allowInsecureAuth=false, the gateway closes with:

ws closed before connect ... reason=control ui requires device identity
(use HTTPS or localhost secure context)

The relevant path appears to be evaluateMissingDeviceIdentity returning reject-control-ui-insecure-auth for any client classified as an operator-UI client (isOperatorUiClient) when no device identity is present.

What I tried

client.idclient.modeHandshakeoperator.write retainedNotes
openclaw-tuiuirejectedn/aclassified as operator-UI client → device-identity check fails
gateway-clientbackendacceptednoscopes stripped (clearUnboundScopes) when no device identity
clicliacceptednosame scope-stripping; isGatewayCliClient accepts the conn but bound scopes are dropped

I also tried openclaw devices rotate --device <name> --role operator --scope operator.write --token <gateway_token> to mint a device token I could pass as auth.deviceToken. The rotation call itself fails with device token rotation denied — apparently because the CLI client running the rotation also has its scopes stripped under the same flag, so there's a chicken-and-egg situation for first-time pairing of a backend service.

What the audit text suggests vs. what actually happens

The security audit message says:

Fix: Disable it or switch to HTTPS (Tailscale Serve) or localhost.

…but a service connecting from 127.0.0.1 to a loopback-bound gateway IS already on localhost. The handshake check does not appear to short-circuit on isLocalClient && isLoopbackHost(origin) for non-Control-UI client classes, so a loopback origin alone is not enough.

Proposed resolutions (any one would close this)

  1. Add a local-service client class that, when the connection is verified-loopback AND auth'd via gateway.auth.token, retains its requested scopes without requiring device pairing.
  2. Add a gateway.trustedLocalServices allowlist in config — list of client.id values that may request operator scopes via gateway-token auth from loopback origins.
  3. Document the supported pairing path for headless backend services — the current openclaw devices CLI commands assume an interactive operator with an already-paired device.
  4. At minimum: improve the audit message to explain that loopback alone is insufficient for non-Control-UI clients under this flag, and point to the recommended pairing flow.

Why this matters

The intent of allowInsecureAuth=false is to prevent Control UI sessions from being authenticated over an insecure transport — a legitimate concern for reverse-proxied or remote setups. But on a single-user, loopback-only host with no reverse proxy and no remote access, the flag's security benefit approaches zero while its cost is that essentially every local backend integration that wants to use the gateway WS API breaks.

Workaround in use

Leaving gateway.controlUi.allowInsecureAuth=true, accepting the audit warning, in setups where all of the following hold:

  • gateway.bind=loopback
  • No reverse proxy in front of the gateway
  • No remote access path to the gateway port
  • Single OS user
  • Gateway token protected by filesystem permissions

extent analysis

TL;DR

To resolve the issue, consider adding a local-service client class that retains requested scopes without requiring device pairing for loopback connections authenticated via gateway.auth.token.

Guidance

  • Review the proposed resolutions in the issue, specifically the suggestion to add a local-service client class or a gateway.trustedLocalServices allowlist, to determine the best approach for your setup.
  • Verify that the connection is indeed coming from a loopback origin and is authenticated using the gateway.auth.token to ensure the security benefits of allowInsecureAuth=false are maintained.
  • If implementing a custom solution, ensure that it does not introduce security vulnerabilities by improperly handling device identities or scopes.
  • Consider the workaround currently in use, leaving gateway.controlUi.allowInsecureAuth=true, but be aware of the associated security audit warning and ensure it is acceptable for your specific setup.

Example

No code example is provided as the issue does not specify a particular implementation detail that can be safely inferred.

Notes

The solution may vary depending on the specific requirements and constraints of the setup, including the version of OpenClaw being used and the security policies in place.

Recommendation

Apply a workaround, such as adding a local-service client class, as it seems to be the most straightforward way to address the issue while maintaining the security benefits of allowInsecureAuth=false. This approach allows for a more flexible and secure way to handle loopback connections from local backend services.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING