Skip to content

fix(auth): propagate scope-mismatch reason instead of collapsing to device_token_mismatch#79314

Closed
Bartok9 wants to merge 1 commit into
openclaw:mainfrom
Bartok9:fix/79292-auth-scope-mismatch-error-propagation
Closed

fix(auth): propagate scope-mismatch reason instead of collapsing to device_token_mismatch#79314
Bartok9 wants to merge 1 commit into
openclaw:mainfrom
Bartok9:fix/79292-auth-scope-mismatch-error-propagation

Conversation

@Bartok9

@Bartok9 Bartok9 commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #79292

When verifyDeviceToken returns { ok: false, reason: 'scope-mismatch' }, resolveConnectAuthDecision was discarding that reason and always emitting device_token_mismatch. This caused the gateway to show users a misleading error ("rotate/reissue device token") when the actual problem is that the connecting client requested scopes beyond what the stored device token allows — specifically operator.admin and operator.pairing which bootstrap tokens do not include.

Root cause

VerifyDeviceTokenResult was typed as { ok: boolean } with no reason field, so the scope-mismatch reason from verifyDeviceToken was silently lost. resolveConnectAuthDecision then fell back to the generic device_token_mismatch string for explicit device tokens.

Changes

  • auth-context.ts: Widen VerifyDeviceTokenResult to include reason?: string. When the reason is scope-mismatch, propagate it as scope_mismatch on the auth result instead of using the generic fallback.
  • connect-error-details.ts: Add AUTH_DEVICE_TOKEN_SCOPE_MISMATCH error code and map scope_mismatch reason in resolveAuthConnectErrorDetailCode.
  • auth-messages.ts: Add human-readable message for scope_mismatch: "unauthorized: device token scope mismatch (re-pair or approve scope upgrade in Control UI)"
  • auth-context.test.ts: Regression test verifying scope-mismatch propagation.

Before / After

Scenario Before After
Client requests operator.admin but token only has 4 bootstrap scopes device_token_mismatch → "rotate/reissue device token" scope_mismatch → "device token scope mismatch (re-pair or approve scope upgrade)"
Token value actually wrong device_token_mismatch (correct) device_token_mismatch (unchanged)

Testing

pnpm vitest run src/gateway/server/ws-connection/auth-context.test.ts
# 10 tests, all pass

Real behavior proof

Executed directly on a running OpenClaw host (Node v25.5.0, 2026-05-08T08:37:58Z). Demonstrates the before/after behavior of the auth decision function:

Scenario A: client requests operator.admin (scope-mismatch from verifyDeviceToken)

BEFORE fix: device_token_mismatch
AFTER fix:  scope_mismatch

Scenario B: token value is actually wrong (genuine mismatch — unchanged)

BEFORE fix: device_token_mismatch
AFTER fix:  device_token_mismatch

User-facing error message:

scope-mismatch BEFORE: "unauthorized: device token mismatch (rotate/reissue device token)"
scope-mismatch AFTER:  "unauthorized: device token scope mismatch (re-pair or approve scope upgrade in Control UI)"

macOS/iOS/Control UI clients request operator.admin + operator.pairing on connect, but bootstrap tokens only include 4 scopes. Before this fix, verifyDeviceToken returned scope-mismatch but resolveConnectAuthDecision discarded it and showed the generic "rotate/reissue device token" message, causing users to delete valid paired devices and re-pair unnecessarily.

…evice_token_mismatch

When verifyDeviceToken returns { ok: false, reason: 'scope-mismatch' },
resolveConnectAuthDecision was discarding that reason and always emitting
'device_token_mismatch'. This caused the gateway to tell the user their
token value was wrong (rotate/reissue) when the real problem was that the
connected client requested scopes beyond what the stored device token
allows (e.g. operator.admin / operator.pairing which bootstrap tokens
do not include).

Changes:
- auth-context.ts: propagate scope-mismatch reason as scope_mismatch
  (also widens VerifyDeviceTokenResult to include optional reason)
- connect-error-details.ts: add AUTH_DEVICE_TOKEN_SCOPE_MISMATCH code
  and map scope_mismatch in resolveAuthConnectErrorDetailCode
- auth-messages.ts: human-readable message directing users to re-pair
  or approve a scope upgrade
- auth-context.test.ts: regression test for scope-mismatch propagation

Fixes openclaw#79292
@Bartok9
Bartok9 requested a review from a team as a code owner May 8, 2026 08:36
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 8, 2026
@clawsweeper

clawsweeper Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR propagates device-token scope mismatches through gateway connect auth, maps them to a new connect error detail code, adds message copy, and adds an auth-context regression test.

Reproducibility: yes. Current main's verifier returns scope-mismatch, while the auth decision path collapses explicit device-token failures to device_token_mismatch; the PR body also includes live before/after output.

Real behavior proof
Sufficient (live_output): The PR body includes copied live-host output showing the after-fix auth decision and user-facing message for scope mismatch, plus unchanged behavior for a genuine token mismatch.

Next step before merge
The remaining repair is narrow and mechanical: wire the new scope-mismatch detail code through client reconnect/error handling and tests without changing the broader pairing policy.

Security
Cleared: The diff changes auth diagnostics and protocol classification only; I found no concrete access-control, secret-handling, dependency, CI, or supply-chain regression.

Review findings

  • [P2] Handle the new scope-mismatch code in clients — src/gateway/protocol/connect-error-details.ts:14
Review details

Best possible solution:

Merge a revised version that propagates scope mismatch end-to-end, including client pause/error handling and regression coverage that preserves stored tokens for scope mismatches.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main's verifier returns scope-mismatch, while the auth decision path collapses explicit device-token failures to device_token_mismatch; the PR body also includes live before/after output.

Is this the best way to solve the issue?

No, not yet. Server-side propagation is the right direction, but the new protocol detail code needs matching handling in the TypeScript, Swift, and Android clients so reconnect and user guidance behavior remains correct.

Full review comments:

  • [P2] Handle the new scope-mismatch code in clients — src/gateway/protocol/connect-error-details.ts:14
    Adding AUTH_DEVICE_TOKEN_SCOPE_MISMATCH changes the detail code sent to Control UI, the shared Gateway client, Swift OpenClawKit, and Android, but this patch does not teach those clients that this auth failure should pause reconnects and surface actionable guidance. Unknown auth codes currently fall through as recoverable, so a real scope mismatch can keep reconnecting instead of stopping without clearing the stored device token.
    Confidence: 0.87

Overall correctness: patch is incorrect
Overall confidence: 0.89

Acceptance criteria:

  • pnpm test src/gateway/server/ws-connection/auth-context.test.ts src/gateway/reconnect-gating.test.ts src/gateway/client.test.ts ui/src/ui/gateway.node.test.ts
  • pnpm test ui/src/ui/connect-error.test.ts ui/src/ui/views/overview.node.test.ts
  • cd apps/shared/OpenClawKit && swift test --filter GatewayErrorsTests
  • cd apps/android && ./gradlew testDebugUnitTest --tests 'Gateway'

What I checked:

  • Current verifier emits scope mismatch: Current main's device-token verifier returns scope-mismatch when the stored token scopes or requested scopes exceed the approved baseline. (src/infra/device-pairing.ts:915, a8c745a6230e)
  • Current auth decision masks that reason: Current main still maps failed explicit device-token checks to device_token_mismatch, discarding the verifier's specific reason. (src/gateway/server/ws-connection/auth-context.ts:219, a8c745a6230e)
  • PR diff adds a new protocol detail code: The live PR diff adds AUTH_DEVICE_TOKEN_SCOPE_MISMATCH and maps scope_mismatch to it, while changing only four server/protocol/test files. (src/gateway/protocol/connect-error-details.ts:14, 238f0c0d8e7b)
  • Client reconnect gates do not handle the new code: Control UI and the shared Gateway client only pause for the existing auth detail codes, including AUTH_DEVICE_TOKEN_MISMATCH; a new code would currently fall through the unknown-code path. (src/gateway/client.ts:689, a8c745a6230e)
  • Native clients also special-case known token errors: Swift OpenClawKit and Android currently special-case existing device-token mismatch handling, so the new code needs matching client behavior to avoid unknown-error reconnect handling. (apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayErrors.swift:4, a8c745a6230e)
  • PR body includes real behavior proof: The PR body includes copied live-host before/after output showing device_token_mismatch before the fix, scope_mismatch after the fix, and unchanged genuine token mismatch behavior. (238f0c0d8e7b)

Likely related people:

  • steipete: Recent path history shows repeated work on device-token scope containment, narrowed token scopes, stale device-token reconnect loops, and related gateway/client files. (role: recent area contributor; confidence: high; commits: c9053ff20853, 8bbb143ab87e, 885806d5ca8d; files: src/infra/device-pairing.ts, src/gateway/client.ts, ui/src/ui/gateway.ts)
  • obviyus: Recent history includes pairing connect detail-code enrichment and Android gateway auth handling that are directly adjacent to this PR's new detail code. (role: protocol and Android auth contributor; confidence: medium; commits: f070a92e19fb, 4e01916a7e1b, dcf821cfb62b; files: src/gateway/protocol/connect-error-details.ts, apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewaySession.kt)
  • joshavant: The documented token fallback and reconnect gating behavior came through the gateway hardening work that this new detail code must preserve. (role: reconnect behavior contributor; confidence: medium; commits: a76e81019333; files: src/gateway/client.ts, docs/gateway/protocol.md)
  • ngutman: Swift OpenClawKit gateway error mapping and connection-problem UX history points here for native client presentation and pause behavior. (role: iOS gateway error UX contributor; confidence: medium; commits: 6380c872bcc2, 28955a36e7b0; files: apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayErrors.swift, apps/shared/OpenClawKit/Sources/OpenClawKit/GatewayConnectionProblem.swift)

Remaining risk / open question:

  • The new detail code can be treated as an unknown recoverable auth error by existing clients, causing reconnect churn or generic presentation instead of stable scope-upgrade guidance.

Codex review notes: model gpt-5.5, reasoning high; reviewed against a8c745a6230e.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
BunsDev added a commit that referenced this pull request May 11, 2026
Preserve full shared-token operator sessions while reusing bootstrap/cached device-token scopes for handoff reconnects.

Surface device-token scope mismatches as AUTH_SCOPE_MISMATCH and stop reconnect retry loops without clearing valid stored tokens.

Fixes #79292.
Supersedes #79314, #79296, #79295.
@BunsDev

BunsDev commented May 11, 2026

Copy link
Copy Markdown
Contributor

Thanks for the focused fix here. This has now been superseded by the broader maintainer landing in #80189, merged as 51b73b3.

That landed the same diagnostic preservation goal and also covered the bootstrap/cached device-token scope contract plus reconnect-loop behavior for AUTH_SCOPE_MISMATCH, so keeping this PR open would duplicate already-landed work.

@BunsDev BunsDev closed this May 11, 2026
steipete pushed a commit that referenced this pull request May 12, 2026
Preserve full shared-token operator sessions while reusing bootstrap/cached device-token scopes for handoff reconnects.

Surface device-token scope mismatches as AUTH_SCOPE_MISMATCH and stop reconnect retry loops without clearing valid stored tokens.

Fixes #79292.
Supersedes #79314, #79296, #79295.
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Preserve full shared-token operator sessions while reusing bootstrap/cached device-token scopes for handoff reconnects.

Surface device-token scope mismatches as AUTH_SCOPE_MISMATCH and stop reconnect retry loops without clearing valid stored tokens.

Fixes openclaw#79292.
Supersedes openclaw#79314, openclaw#79296, openclaw#79295.
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
Preserve full shared-token operator sessions while reusing bootstrap/cached device-token scopes for handoff reconnects.

Surface device-token scope mismatches as AUTH_SCOPE_MISMATCH and stop reconnect retry loops without clearing valid stored tokens.

Fixes openclaw#79292.
Supersedes openclaw#79314, openclaw#79296, openclaw#79295.
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Preserve full shared-token operator sessions while reusing bootstrap/cached device-token scopes for handoff reconnects.

Surface device-token scope mismatches as AUTH_SCOPE_MISMATCH and stop reconnect retry loops without clearing valid stored tokens.

Fixes openclaw#79292.
Supersedes openclaw#79314, openclaw#79296, openclaw#79295.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(auth): operator scope mismatch silently rejected as device token mismatch

2 participants