Skip to content

Loopback token-auth CLI connects but RPC is scope-limited (missing operator.read/write) #46650

@DmytroVolodymyrson

Description

@DmytroVolodymyrson

Summary

openclaw CLI can connect successfully to a local loopback gateway over shared token auth, but the session lands in a scope-limited operator state and RPC calls fail with errors like:

  • missing scope: operator.read
  • missing scope: operator.write

This breaks control-plane operations such as:

  • openclaw gateway probe
  • openclaw cron add
  • openclaw cron runs

Environment

  • OpenClaw package version: 2026.3.13
  • Gateway mode: local
  • Gateway bind: loopback
  • Gateway auth mode: token
  • Target URL: ws://127.0.0.1:18789
  • CLI invoked from Cedric via exec, using the local openclaw CLI

Repro

From the same machine as the gateway:

openclaw gateway probe --token <gateway-token> --url ws://127.0.0.1:18789

Observed result:

  • transport/auth connect succeeds
  • but probe reports degraded RPC auth, e.g.
Reachable: yes
Connect: ok
RPC: limited - missing scope: operator.read

And in gateway logs we see:

[ws] ⇄ res ✗ status 1ms errorCode=INVALID_REQUEST errorMessage=missing scope: operator.read
[ws] ⇄ res ✗ system-presence 1ms errorCode=INVALID_REQUEST errorMessage=missing scope: operator.read
[ws] ⇄ res ✗ config.get 1ms errorCode=INVALID_REQUEST errorMessage=missing scope: operator.read

Same class of failure affects cron add / cron runs through the same path.

What we checked already

1. Pairing/auth files looked correct

We verified both of these files contained operator scopes including read/write:

  • ~/.openclaw/identity/device-auth.json
  • ~/.openclaw/devices/paired.json

Scopes present:

  • operator.admin
  • operator.approvals
  • operator.pairing
  • operator.read
  • operator.write

We also restarted the gateway after correcting a mismatch there. The problem persisted.

2. Internal code path investigation

The installed code suggests this local-loopback path intentionally avoids attaching device identity for token/password-authenticated gateway calls.

In our local build we found:

Client side

dist/auth-profiles-*.js

function shouldAttachDeviceIdentityForGatewayCall(params) {
	if (!(params.token || params.password)) return true;
	try {
		const parsed = new URL(params.url);
		return ![
			"127.0.0.1",
			"::1",
			"localhost"
		].includes(parsed.hostname);
	} catch {
		return true;
	}
}

And the gateway client is built with:

deviceIdentity: shouldAttachDeviceIdentityForGatewayCall({
	url,
	token,
	password
}) ? loadOrCreateDeviceIdentity() : void 0,

Server side

dist/gateway-cli-*.js

We found:

function roleCanSkipDeviceIdentity(role, sharedAuthOk) {
	return role === "operator" && sharedAuthOk;
}

and missing-device handling that can clear scopes when no bound device is present:

const clearUnboundScopes = () => {
	if (scopes.length > 0) {
		scopes = [];
		connectParams.scopes = scopes;
	}
};

This appears to produce an awkward state where:

  • shared auth succeeds
  • connection is allowed
  • but effective operator scopes end up empty / limited
  • so subsequent RPC authorization fails

3. Temporary local patch attempt

As a diagnostic only, we patched shouldAttachDeviceIdentityForGatewayCall(...) to always return true in the installed dist bundles.

That still did not fully fix the issue.

So the problem seems deeper than only the loopback identity gate.

Current diagnosis

Most likely the CLI is ending up in a partially authorized operator session on this loopback shared-auth path:

  • connect succeeds
  • operator role is accepted
  • but the client does not arrive with a fully usable device-token-backed scope set for RPC
  • and the client does not automatically upgrade/retry out of this degraded state

In other words:

local loopback + shared token auth can connect, but still leave the operator client scope-limited for gateway RPC.

Why this matters

This blocks a robust local operator workflow where the local openclaw CLI is expected to safely perform:

  • cron registration
  • cron inspection
  • gateway probe/status
  • other control-plane operations

Without this, local automation that depends on control-plane CLI operations becomes much harder to make reliable.

Questions / expected behavior

I think one of these should be true:

  1. Local loopback shared-auth operator CLI calls should attach device identity and establish a fully scoped operator session, or
  2. Local shared-auth operator CLI calls that are intentionally allowed without device identity should still preserve requested operator scopes for RPC, or
  3. The CLI should detect this degraded state and explicitly retry/upgrade into a device-token-backed operator session instead of silently succeeding at connect and failing later on read/write/admin RPCs.

Request

Could you confirm whether this is expected behavior or a bug?

If it is a bug, I’d appreciate guidance on the intended fix path for:

  • local loopback token-authenticated operator CLI
  • from the same machine as the gateway
  • where downstream RPC methods need full operator scopes

If useful, I can also provide a smaller repro focused only on gateway probe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions