Bug
After signing in to the web frontend, auth only works in the tab that completed login. Opening the same frontend in a new browser tab behaves as logged out and requires signing in again.
Reproduction
- Open the ElasticClaw web frontend.
- Sign in with either GitHub OAuth or the access-token/password flow.
- Open a new tab to the same frontend URL.
- Observe that the new tab has no authenticated state and redirects/prompts for login.
Expected behavior
A valid web session should be usable across tabs for the same browser/profile until the session expires or the user signs out.
Actual behavior
The session token is stored in sessionStorage, which is scoped to the current top-level browsing context. A newly opened tab starts with empty sessionStorage, so the frontend sends no bearer token and the app treats the user as logged out.
Diagnosis
The login page writes both successful auth flows into tab-local storage:
- GitHub OAuth callback stores
ec_github_token with sessionStorage.setItem(...) in web/app/login/page.tsx around lines 78-81.
- Token/password login stores
ec_hub_token with sessionStorage.setItem(...) in web/app/login/page.tsx around lines 109-111.
The API client then resolves auth only from that same per-tab storage:
resolveToken() checks sessionStorage.getItem("ec_github_token") and sessionStorage.getItem("ec_hub_token") in web/lib/api.ts around lines 19-29.
getTokenSync() also reads only those sessionStorage keys in web/lib/api.ts around lines 52-57.
The main page repeats the same pattern when checking /api/auth/me:
web/app/page.tsx reads auth status from sessionStorage around lines 29-39.
The backend signed GitHub session token is valid for 7 days (githubSessionExpiry in pkg/hub/auth_github.go around line 22), so the short-lived behavior is not from the backend token lifetime. It is from frontend storage scope.
Likely fix
Use a browser-wide session mechanism instead of tab-local sessionStorage. Two reasonable options:
- Preferred: set an HttpOnly, Secure, SameSite cookie from the hub for web auth and have frontend/API calls authenticate via cookie where possible. This avoids exposing long-lived session tokens to JavaScript and naturally works across tabs.
- Smaller frontend-only fix: store the session token in
localStorage and update all auth reads/writes/clear paths from sessionStorage to a shared helper. This restores cross-tab behavior but keeps the token JavaScript-readable.
Whichever fix is chosen, centralize token access in web/lib/api.ts or a dedicated auth storage helper; several files currently read the auth keys directly (web/app/page.tsx, web/components/sidebar.tsx, settings pages, branding hook). Add coverage or a manual test that login in one tab allows loading the app in a second tab without another sign-in.
Bug
After signing in to the web frontend, auth only works in the tab that completed login. Opening the same frontend in a new browser tab behaves as logged out and requires signing in again.
Reproduction
Expected behavior
A valid web session should be usable across tabs for the same browser/profile until the session expires or the user signs out.
Actual behavior
The session token is stored in
sessionStorage, which is scoped to the current top-level browsing context. A newly opened tab starts with emptysessionStorage, so the frontend sends no bearer token and the app treats the user as logged out.Diagnosis
The login page writes both successful auth flows into tab-local storage:
ec_github_tokenwithsessionStorage.setItem(...)inweb/app/login/page.tsxaround lines 78-81.ec_hub_tokenwithsessionStorage.setItem(...)inweb/app/login/page.tsxaround lines 109-111.The API client then resolves auth only from that same per-tab storage:
resolveToken()checkssessionStorage.getItem("ec_github_token")andsessionStorage.getItem("ec_hub_token")inweb/lib/api.tsaround lines 19-29.getTokenSync()also reads only thosesessionStoragekeys inweb/lib/api.tsaround lines 52-57.The main page repeats the same pattern when checking
/api/auth/me:web/app/page.tsxreads auth status fromsessionStoragearound lines 29-39.The backend signed GitHub session token is valid for 7 days (
githubSessionExpiryinpkg/hub/auth_github.goaround line 22), so the short-lived behavior is not from the backend token lifetime. It is from frontend storage scope.Likely fix
Use a browser-wide session mechanism instead of tab-local
sessionStorage. Two reasonable options:localStorageand update all auth reads/writes/clear paths fromsessionStorageto a shared helper. This restores cross-tab behavior but keeps the token JavaScript-readable.Whichever fix is chosen, centralize token access in
web/lib/api.tsor a dedicated auth storage helper; several files currently read the auth keys directly (web/app/page.tsx,web/components/sidebar.tsx, settings pages, branding hook). Add coverage or a manual test that login in one tab allows loading the app in a second tab without another sign-in.