fix(auth): surface distinct scope-mismatch reason for device token failures#79296
fix(auth): surface distinct scope-mismatch reason for device token failures#79296hclsys wants to merge 1 commit into
Conversation
…ilures
When verifyDeviceToken returns reason="scope-mismatch" (the device token's
approved scopes do not cover the requested connection scopes), the auth
pipeline previously collapsed this into the generic device_token_mismatch
error, causing clients to rotate/reissue a perfectly valid token.
Surface a distinct device_token_scope_mismatch reason and error message
("re-pair this device to request the current scope set") so clients can
take the right corrective action. Adds AUTH_DEVICE_TOKEN_SCOPE_MISMATCH
error detail code for protocol-level classification.
Fixes openclaw#79292.
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: yes. for the source-level seam: current main can return Real behavior proof Next step before merge Security Review findings
Review detailsBest possible solution: Land the diagnostic propagation together with matching terminal/re-pair handling in the affected TS and native clients, plus redacted real gateway/client evidence showing the scope-mismatch recovery path. Do we have a high-confidence way to reproduce the issue? Yes for the source-level seam: current main can return Is this the best way to solve the issue? No as currently patched: carrying the verifier reason forward is the right narrow server fix, but emitting a new public detail code without updating client recovery gates makes the reported recovery path incomplete. Full review comments:
Overall correctness: patch is incorrect What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against dce9261415f7. |
This comment was marked as low quality.
This comment was marked as low quality.
This comment was marked as low quality.
This comment was marked as low quality.
|
🦞🧹 Reason: re-review requires an open issue or PR. |
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.
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.
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.
Summary
When
verifyDeviceTokenreturnsreason: "scope-mismatch"(the token's approved scopes do not cover the requested connection scopes), the auth pipeline collapsed this into the genericdevice_token_mismatcherror and message — misleading clients into rotating/reissuing a perfectly valid token.VerifyDeviceTokenResulttype to includereason?: stringscope-mismatchas a distinctdevice_token_scope_mismatchreasonAUTH_DEVICE_TOKEN_SCOPE_MISMATCHerror detail code toConnectErrorDetailCodes"device_token_scope_mismatch"message case: "unauthorized: device token scope mismatch (re-pair this device to request the current scope set)"verifyDeviceTokenreturningscope-mismatch→authResult.reason === "device_token_scope_mismatch"Fixes #79292.
Root cause
macOS/iOS/Control UI clients request 5 scopes (
operator.admin,operator.read,operator.write,operator.approvals,operator.pairing). Bootstrap token issuance stripsoperator.adminandoperator.pairing(the allowlist only has 4), so the stored device token has 4 scopes. On reconnect with 5 scopes,verifyDeviceTokenat line 896/900 ofdevice-pairing.tsreturns{ ok: false, reason: "scope-mismatch" }.resolveConnectAuthDecisiondropped thereasonfield (the localVerifyDeviceTokenResulttype was{ ok: boolean }) and emitteddevice_token_mismatch— the wrong diagnosis.Real behavior proof
verifyDeviceTokenreturnsreason: "scope-mismatch",resolveConnectAuthDecisionlost the reason field (type was{ ok: boolean }, noreasonfield) and emitted genericdevice_token_mismatch. This PR extendsVerifyDeviceTokenResultwithreason?: stringand branches on"scope-mismatch"to emitdevice_token_scope_mismatchinstead.1a7612f0be29147180072a0fb218f44449ce24c6, tsx for direct TypeScript import.node --import tsx /tmp/proof_79296.mjswhere the script callsresolveConnectAuthDecisiondirectly with averifyDeviceTokenstub returning{ ok: false, reason: "scope-mismatch" }and asserts the returnedauthResult.reason.resolveConnectAuthDecisionreturnsauthResult.reason === "device_token_scope_mismatch"whenverifyDeviceTokenreturns{ ok: false, reason: "scope-mismatch" }. Before this patch theVerifyDeviceTokenResulttype had noreasonfield — the value was silently discarded and the genericdevice_token_mismatchreason was emitted instead.Test plan
src/gateway/server/ws-connection/auth-context.test.ts— new test: scope-mismatch reason propagates asdevice_token_scope_mismatch; all 30 tests passsrc/gateway/protocol/connect-error-details.test.ts— all 26 tests passformatGatewayAuthFailureMessageorreadConnectAuthDecisionErrorDetailCodeneed changes🤖 Generated with Claude Code