Skip to content

fix(ui): preserve login across same-origin gateways#101352

Merged
fuller-stack-dev merged 3 commits into
openclaw:mainfrom
fuller-stack-dev:codex/fix-control-ui-device-token-scope
Jul 7, 2026
Merged

fix(ui): preserve login across same-origin gateways#101352
fuller-stack-dev merged 3 commits into
openclaw:mainfrom
fuller-stack-dev:codex/fix-control-ui-device-token-scope

Conversation

@fuller-stack-dev

Copy link
Copy Markdown
Member

Closes #101351

Related: #40892
Related: #99903
Related: #43037

What Problem This Solves

Fixes an issue where users with multiple Control UI gateways on the same HTTPS origin could be logged out of one gateway after authenticating another gateway on a different path or query route. A fresh Rosita tab could send Wilfred's cached device token, fail the gateway handshake, and ask for the shared token again even though that token had not changed.

Why This Change Was Made

The browser now stores gateway-issued device credentials under the exact normalized gateway endpoint, including protocol, host, path, and query while excluding the fragment. Device identity remains shared, but each gateway reuses only its own device-bound token. On upgrade, the legacy origin-wide record is claimed by the first gateway that opens, migrated to that exact scope, and deleted so sibling routes cannot consume it.

This deliberately does not broadcast the shared gateway token between tabs or persist it in localStorage. Fresh tabs continue to rely on the existing revocable, device-bound credential issued by the gateway.

User Impact

Users running multiple gateways behind one origin can open or reload each Control UI without another gateway's login overwriting it. Updates and restarts no longer appear to rotate the gateway token when the actual failure is a mismatched cached device credential.

Evidence

  • Regression test failed before the fix because a Rosita connection received wilfred-device-token instead of rosita-device-token.
  • Unit coverage verifies isolation for same-origin path routes and query routes.
  • Upgrade coverage verifies migration of the legacy unscoped record and continued auth when best-effort cleanup fails.
  • Chromium E2E verifies that an independently opened tab reconnects with the gateway-issued device token and does not show the login gate.
  • Full Control UI test suite: 141 files and 2,287 tests passed.
  • Final focused auth/settings suite: 71 tests passed.
  • Focused type-aware lint: passed.
  • Chromium E2E: 1 test passed.
  • Full Linux production build: passed on Crabbox run run_a1c2bad51772.
  • Final exact-head Control UI build: passed on Crabbox run run_ac93d992f1da.
  • Final post-rebase auth/settings suite: 71 tests passed on Crabbox run run_fb102f7a6179.
  • Local autoreview: clean, no actionable findings.

Security Impact

Yes: this changes browser credential storage. The change narrows each bearer credential to its issuing gateway endpoint and intentionally avoids copying the master gateway token into persistent or cross-tab storage.

AI Assistance

AI-assisted. The implementation and tests were reviewed with the repository's local autoreview workflow. No agent transcript is attached.

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: M maintainer Maintainer-authored PR labels Jul 7, 2026
@clawsweeper

clawsweeper Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 7, 2026, 1:05 AM ET / 05:05 UTC.

Summary
The PR scopes Control UI browser device-auth credentials by normalized gateway endpoint, migrates the legacy origin-wide record, and adds unit plus Chromium E2E coverage.

PR surface: Source +106, Tests +210. Total +316 across 7 files.

Reproducibility: yes. from source: current main uses one browser device-auth key for all gateway URLs, which matches the linked same-origin gateway collision report. I did not run the new regression test in this read-only pass.

Review metrics: 1 noteworthy metric.

  • Browser credential storage migration: 1 legacy origin-wide key replaced by gateway-scoped keys. This is the upgrade-sensitive surface maintainers need to notice before merging the auth fix.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #101351
Summary: This PR is the candidate fix for the same-origin gateway device-token collision issue; related Control UI auth reports are adjacent or partial overlaps rather than replacements.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Clear or explain the unrelated checks-node-compact-small-whole-1 failure before merge if it remains on the exact head.

Risk before merge

  • [P1] The diff changes browser-persisted credential keying; maintainers should explicitly accept the upgrade behavior where the ambiguous legacy record is claimed by the first gateway opened and then removed.
  • [P1] One unrelated live CI shard failed in src/cli/hooks-cli.process.test.ts; I did not treat it as a PR code finding because the failing path is outside the touched Control UI auth surface.

Maintainer options:

  1. Land with explicit migration acceptance (recommended)
    Accept the compatibility tradeoff that one legacy device-auth record can only be safely assigned to the first opened gateway, with tests covering path/query isolation afterward.
  2. Change migration to force re-auth
    Before merge, change the browser migration to discard the ambiguous legacy key and require each gateway to mint its own scoped device token.

Next step before merge

  • [P2] Protected maintainer-authored PR with an intentional credential-storage migration should continue through maintainer review rather than an automated repair lane.

Maintainer decision needed

  • Question: Is the legacy origin-wide browser device-auth record allowed to be claimed by the first gateway opened after upgrade and then deleted?
  • Rationale: The old browser record cannot identify which same-origin gateway issued it, so the migration choice affects upgrade behavior for users with multiple path/query-routed gateways.
  • Likely owner: Peter Steinberger — The current checked-in UI auth/storage paths and security-boundary policy trace to this history, making this the best available owner signal for the migration choice.
  • Options:
    • Accept claim-on-first-open migration (recommended): Keep this PR's migration, which preserves one usable token and prevents the ambiguous legacy token from being replayed to sibling gateways.
    • Force fresh scoped credentials: Change the migration to discard the ambiguous legacy key and require each gateway to mint its own scoped device token after upgrade.

Security
Cleared: No concrete security or supply-chain regression found; the diff narrows device-token scope and does not persist the shared gateway token.

Review details

Best possible solution:

Land the scoped device-token storage fix with the included migration and regression coverage after maintainers accept the intentional legacy-record claim-on-first-open behavior and clear the unrelated CI failure.

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

Yes from source: current main uses one browser device-auth key for all gateway URLs, which matches the linked same-origin gateway collision report. I did not run the new regression test in this read-only pass.

Is this the best way to solve the issue?

Yes, this is the best fix shape: scope only the gateway-issued device credential by normalized endpoint while keeping the shared gateway token out of durable cross-tab storage.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 1898afe076b8.

Label changes

Label changes:

  • add P1: The PR fixes a deterministic Control UI authentication failure that can block users running multiple gateways behind one origin.
  • add merge-risk: 🚨 compatibility: The diff changes browser-persisted device-auth keying and migrates an ambiguous legacy credential on upgrade.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This is a maintainer-labeled member PR, so the external-contributor proof gate does not apply; the PR body still lists regression, E2E, suite, lint, build, and Crabbox run evidence.

Label justifications:

  • P1: The PR fixes a deterministic Control UI authentication failure that can block users running multiple gateways behind one origin.
  • merge-risk: 🚨 compatibility: The diff changes browser-persisted device-auth keying and migrates an ambiguous legacy credential on upgrade.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This is a maintainer-labeled member PR, so the external-contributor proof gate does not apply; the PR body still lists regression, E2E, suite, lint, build, and Crabbox run evidence.
Evidence reviewed

PR surface:

Source +106, Tests +210. Total +316 across 7 files.

View PR surface stats
Area Files Added Removed Net
Source 5 146 40 +106
Tests 2 219 9 +210
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 7 365 49 +316

What I checked:

  • Repository policy read: Root and UI-scoped AGENTS.md were read fully; auth/session state and persisted credential changes are compatibility-sensitive under repository policy. (AGENTS.md:34, 1898afe076b8)
  • Current main root cause: Current main stores browser device auth in one openclaw.device.auth.v1 key without a gateway URL dimension, matching the linked same-origin gateway collision report. (ui/src/lib/nodes/index.ts:145, 1898afe076b8)
  • PR scopes browser auth operations: At the PR head, GatewayBrowserClient passes gatewayUrl: this.opts.url when storing, loading, and clearing browser device credentials. (ui/src/api/gateway.ts:820, c85d917cc3b4)
  • PR migration implementation: The PR adds gateway-scoped device-auth storage keys, claims a legacy store for the first opened gateway, and removes the ambiguous legacy key with best-effort cleanup. (ui/src/lib/nodes/index.ts:445, c85d917cc3b4)
  • Regression coverage: The PR adds tests for legacy migration, cleanup failure tolerance, same-origin path isolation, and query-route isolation. (ui/src/api/gateway.node.test.ts:964, c85d917cc3b4)
  • Browser E2E coverage: The new E2E opens an authenticated tab, then verifies a separate tab reconnects with the gateway-issued device token and does not show the login gate. (ui/src/e2e/device-token-reconnect.e2e.test.ts:50, c85d917cc3b4)

Likely related people:

  • Peter Steinberger: git blame and git log -S show the current ui/src/lib/nodes/index.ts, ui/src/app/settings.ts, and ui/src/api/gateway.ts paths entering the checked-out history in commit 95f4674. (role: introduced current checked-in UI auth/storage paths; confidence: medium; commits: 95f46743e4de; files: ui/src/lib/nodes/index.ts, ui/src/app/settings.ts, ui/src/api/gateway.ts)
  • velvet-shark: Merged PR fix(ui): preserve control-ui auth across refresh #40892 changed the same Control UI token persistence boundary while keeping shared gateway tokens session-scoped. (role: adjacent auth preservation contributor; confidence: high; commits: f2f561fab1bf; files: ui/src/ui/storage.ts, ui/src/ui/storage.node.test.ts)
  • Vincent Koc: git log -S shows current shared device-auth helper history in the release commit that includes src/shared/device-auth-store.ts, an adjacent contract consumed by this PR's browser adapter. (role: shared device-auth helper history; confidence: low; commits: e085fa1a3ffd; files: src/shared/device-auth-store.ts, src/shared/device-auth.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jul 7, 2026
@fuller-stack-dev

Copy link
Copy Markdown
Member Author

Land-ready verification for 7bdf6e6fd3c2b406c2396e569066028c7e5e369a:

  • Canonical-fix verdict: this is the only exact fix found for [Bug]: Control UI device tokens collide across same-origin gateway paths #101351; adjacent PRs cover different master-token, lifecycle, loopback-alias, retry, or broader hardening concerns.
  • Security boundary: browser device identity remains origin-shared, while gateway-issued bearer credentials are scoped by normalized protocol, host, path, and query. Sibling paths and other origins cannot read or clear each other's tokens, and shared gateway tokens remain sessionStorage-only.
  • Migration: the ambiguous legacy origin-wide record is claimed by at most the first exact gateway opened after upgrade, then removed.
  • Deterministic Chromium E2E: 1/1 passed for /rosita and /wilfred token isolation, a separate-origin negative control, Nodes-page revoke, sibling-token retention, and revoked-token absence.
  • Focused UI tests: 3 files, 75/75 passed (ui/src/api/gateway.node.test.ts, ui/src/app/settings.node.test.ts, ui/src/pages/nodes/view.devices.test.ts).
  • oxfmt --check, git diff --check, and fresh Codex autoreview passed with no actionable findings.
  • Exact-head hosted CI run 28846816306 is fully green: https://github.com/openclaw/openclaw/actions/runs/28846816306
  • Sanitized AWS Crabbox warmup returned HTTP 401 before lease allocation or code execution, so focused browser/unit proof used the repository-approved narrow local fallback. Visual screenshots were captured and left uncommitted.
  • No rebase or contributor-history rewrite was performed; the preparation commit was a lease-pinned fast-forward.

Proceeding with the deterministic squash merge pinned to the prepared head.

@fuller-stack-dev
fuller-stack-dev merged commit e024eac into openclaw:main Jul 7, 2026
84 of 86 checks passed
@fuller-stack-dev

Copy link
Copy Markdown
Member Author

Merged via squash.

@fuller-stack-dev
fuller-stack-dev deleted the codex/fix-control-ui-device-token-scope branch July 7, 2026 06:51
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 7, 2026
* fix(ui): scope device auth by gateway

* fix(ui): migrate legacy device auth storage

* test(ui): cover gateway device-token isolation
sheyanmin pushed a commit to sheyanmin/openclaw that referenced this pull request Jul 8, 2026
* fix(ui): scope device auth by gateway

* fix(ui): migrate legacy device auth storage

* test(ui): cover gateway device-token isolation
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
* fix(ui): scope device auth by gateway

* fix(ui): migrate legacy device auth storage

* test(ui): cover gateway device-token isolation
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 maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Control UI device tokens collide across same-origin gateway paths

2 participants