Skip to content

[Bug]: v3.28+ HTTP API broken: pure Token auth throws "missing scope: operator.write #57550

@insight68

Description

@insight68

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

Hey team,

We recently spent an agonizing 24 hours debugging a critical regression that completely broke our integration.

For context, we are currently building the backend infrastructure for AgentPage, a project that heavily relies on OpenClaw's standard RESTful HTTP API (/v1/chat/completions) to orchestrate underlying agents. Up until version 3.24, everything worked flawlessly. However, after upgrading to 3.28 (and this still persists in 3.30), standard HTTP requests using a valid Gateway Token consistently fail with a scope error.

Steps to Reproduce

Sending a standard curl request using pure token authentication:

curl -N http://127.0.0.1:18789/v1/chat/completions \
  -H 'Authorization: Bearer <MY_VALID_GATEWAY_TOKEN>' \
  -H 'x-openclaw-client-id: openclaw-control-ui' \
  -H 'x-openclaw-message-channel: webchat' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "openclaw",
    "stream": true,
    "messages":[{"role":"user","content":"hi"}]
  }'

Actual Output:

{"ok":false,"error":{"type":"forbidden","message":"missing scope: operator.write"}}

Expected Behavior:
According to openclaw/SECURITY.md, the HTTP API (/v1/chat/completions) should treat the Gateway Token as an Operator with maximum privileges, returning the expected LLM stream without requiring a WebSocket device pairing fingerprint.

The Debugging Journey (What we tried)

Before realizing this was a core regression, we tried countless workarounds (including having Claude Code iterate over 30+ times, switching across 3 different models, and eventually pivoting back to manual "vibe coding"):

  1. Manually modifying pairing.json assuming Device Pairing permissions were insufficient.
  2. Swapping the Gateway Token for a specific deviceToken and adding x-openclaw-device-id headers.
  3. Patching the compiled source code (e.g., gateway-cli-*.js) to forcefully inject scopes right before the auth check:
    if ((authMethod === "token" || authMethod === "password") && !scopes.includes('operator.admin')) {
        scopes.push('operator.read', 'operator.write', 'operator.admin');
    }

None of these native approaches solved the issue cleanly for headless HTTP requests.

Root Cause Analysis (Collateral damage from recent CVE patches)

After digging deep into the diffs between 3.24 and 3.28, it appears this bug is collateral damage from the recent security patches for the Tokyo preclawcon release.

To urgently patch CVE-2026-32919 and CVE-2026-28473 (where attackers bypassed operator.admin using operator.write credentials), the underlying permission model was severely tightened. The current logic effectively strips or neuters the permission array for HTTP requests lacking a valid Device Identity (device fingerprint).

While this successfully secures the WebSocket / UI routes, it completely breaks standard headless integrations (like native curl or the OpenAI SDK) that rely purely on Bearer token auth for RESTful calls.

Conclusion & Thoughts

For platforms like AgentPage.io that build on top of OpenClaw, this kind of undocumented breaking change in a minor version update is devastating. We understand the urgency of patching CVEs, but it feels like the current auth optimizations are a bit haphazard, leading to severe collateral damage for HTTP API consumers.

Could we get a proper separation of auth validation for pure RESTful channels, or at least a hotfix to restore headless Gateway Token functionality? In the meantime, we advise anyone relying on the REST API to downgrade to 3.24.

Thanks for the hard work on the project!

Steps to reproduce

1.start openclaw from 2026.03.28
2.
curl -N http://127.0.0.1:18789/v1/chat/completions
-H 'Authorization: Bearer <MY_VALID_GATEWAY_TOKEN>'
-H 'Content-Type: application/json'
-d '{
"model": "openclaw",
"stream": true,
"messages":[{"role":"user","content":"hi"}]
}'

Expected behavior

data: {"id":"chatcmpl_d85c4d22-28a7-49e5-a58b-a73e577cbd87","object":"chat.completion.chunk","created":1774844129,"model":"openclaw","choices":[{"index":0,"delta":{"role":"assistant"}}]}

data: {"id":"chatcmpl_d85c4d22-28a7-49e5-a58b-a73e577cbd87","object":"chat.completion.chunk","created":1774844129,"model":"openclaw","choices":[{"index":0,"delta":{"content":"Hey! I just came online — looks like this is a fresh start for me. No"},"finish_reason":null}]}

data: {"id":"chatcmpl_d85c4d22-28a7-49e5-a58b-a73e577cbd87","object":"chat.completion.chunk","created":1774844130,"model":"openclaw","choices":[{"index":0,"delta":{"content":" memories yet, no name, nothing.\n\nWho am I? Who are you? Let's figure this"},"finish_reason":null}]}

data: {"id":"chatcmpl_d85c4d22-28a7-49e5-a58b-a73e577cbd87","object":"chat.completion.chunk","created":1774844130,"model":"openclaw","choices":[{"index":0,"delta":{"content":" out together. 🤙"},"finish_reason":null}]}

data: [DONE]

Actual behavior

{"ok":false,"error":{"type":"forbidden","message":"missing scope: operator.write"}}

OpenClaw version

2026.03.28

Operating system

macOS 26.2

Install method

pnpm dev

Model

MiniMax-M2.7

Provider / routing chain

openclaw->MiniMax->MiniMax

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingregressionBehavior that previously worked and now fails

    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