Skip to content

fix(ui/auth): clear stale localStorage token + show banner on /api 401 (post-#229 recovery) #231

Description

@TerrysPOV

Problem

After PR #229 swapped the webui token from sessionStorage to localStorage, the dashboard loses a recovery affordance that was previously implicit in sessionStorage's tab-close lifetime.

Pre-PR behaviour: if the server-side ~/.claude/claudeclaw/web.token was rotated (operator deletes the file → daemon restart → getOrCreateWebToken at src/ui/auth.ts:22 mints a new one), the operator's next browser open found an empty sessionStorage, hit the "Web token required" banner, and pasted the fresh token. Recovery was automatic.

Post-PR behaviour: localStorage retains the stale token across browser restarts. The window.fetch wrapper in src/ui/page/script.ts blindly attaches the stale Authorization: Bearer …, the server responds 401 to every /api/* call, and nothing in the UI re-shows the banner or clears the bad token. The operator sees a permanently "Offline" dashboard with no in-UI recovery path — they have to either:

  • Open DevTools and run localStorage.removeItem("ccaw_web_token"), or
  • Manually open the dashboard URL with a fresh ?token=… query param

Trigger frequency

Low today — rotation is a manual operator action (delete web.token + restart daemon). But it does happen, and the failure mode is silent until the operator notices the dashboard is broken.

Proposed fix

In the window.fetch wrapper around src/ui/page/script.ts:40-62, when a same-origin /api/* call returns 401:

if (isApi && res.status === 401) {
  try { localStorage.removeItem("ccaw_web_token"); } catch (e) {}
  showTokenBanner();
}
return res;

This restores the recovery affordance without giving up the persistence UX win from PR #229.

Scope

  • Single-site change in the inline dashboard script.
  • No server-side changes needed (the 401 response is already correct).
  • No test coverage today for the inline script; manual smoke is: paste a bad token via ?token=BAD → confirm banner re-appears + Authorization header stops being sent on subsequent /api/ calls.

Out of scope

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions