Skip to content

fix(server): make Workspace sessions work against a cookie-gated dashboard#692

Open
SherubabaFBC wants to merge 1 commit into
outsourc-e:mainfrom
SherubabaFBC:fix/dashboard-auth-capability-split
Open

fix(server): make Workspace sessions work against a cookie-gated dashboard#692
SherubabaFBC wants to merge 1 commit into
outsourc-e:mainfrom
SherubabaFBC:fix/dashboard-auth-capability-split

Conversation

@SherubabaFBC

Copy link
Copy Markdown

Problem

On remote deployments (Docker / Tailscale) the Hermes dashboard runs behind interactive cookie login. Workspace's dashboard.available capability comes from the public /api/status probe, so it's true even when the dashboard's session APIs are cookie-gated. All eight session adapters route dashboard-first on that flag, so the Sessions tab fails with:

401 {"error":"unauthenticated","reason":"no_cookie"}

The fork's only dashboard-auth path was the inline session-token scrape, which upstream Hermes removed — so it always yields nothing. Separately, the gateway fallback returned resp.items for the OpenAI-compatible {object:"list", data:[...]} shape, crashing callers with Cannot read properties of undefined (reading 'map').

Fix

  • Split dashboard.available (reachable) from dashboard.authenticated — the latter probed against GET /api/sessions?limit=1 through dashboardFetch. Dashboard-backed composites (sessions/skills/config/jobs, mcpFallback) now require authenticated, with the legacy gateway probes as fallback.
  • Cookie login (dashboardLogin()): authenticate via the built-in basic provider — POST /auth/password-login -> session cookie — reused and refreshed on 401, with a failure cooldown to avoid lockout. Credentials via HERMES_DASHBOARD_USERNAME / HERMES_DASHBOARD_PASSWORD; unset preserves the legacy behavior.
  • DashboardAuthError (typed) on 401/403; sessionCall() routes dashboard-first only when authenticated, degrades via markDashboardUnauthenticated() on a mid-flight 401 and falls back to the gateway; asArray() normalizes sessions/items/data so list adapters never return undefined. Applied to all eight session adapters.

Not in scope

~50 other dashboard.available consumers in src/routes/api/* share the reachable-vs-usable assumption; left unchanged here to keep the diff focused — they behave exactly as before.

Testing

  • npx tsc --noEmit: adds 0 new errors (identical count with and without this change).
  • vitest: 34 tests covering the split, cookie login (success/reuse/reject), gateway fallback, and shape normalization — all pass.
  • Verified end-to-end on a live cookie-gated dashboard deployment: sessions, skills, config, and jobs load with the dashboard's auth gate left intact.

…board

On remote/Tailscale deployments the dashboard runs behind interactive cookie
login. `dashboard.available` came from the public `/api/status` probe, so the
session adapters routed dashboard-first and failed with
`401 {"reason":"no_cookie"}` — the fork's only dashboard auth was the removed
inline session-token scrape. Separately, the gateway fallback returned
`resp.items` for the OpenAI-shape `{object:"list", data:[...]}` body, crashing
callers with `.map` on undefined.

- capabilities: split `dashboard.available` (reachable) from
  `dashboard.authenticated` (auth-gated endpoint probe); dashboard-backed
  composites require authenticated, with the legacy gateway probes as fallback
- claude-dashboard-api: typed `DashboardAuthError` on 401/403
- claude-api: `sessionCall()` routes dashboard-first only when authenticated,
  degrades via `markDashboardUnauthenticated()` on mid-flight 401 and falls back
  to the gateway; `asArray()` normalizes sessions/items/data so list adapters
  never return undefined; applied to all eight session adapters
- gateway-capabilities: `dashboardLogin()` authenticates via the built-in
  `basic` provider (POST `/auth/password-login` -> session cookie), reused and
  refreshed on 401, with a failure cooldown; credentials from
  `HERMES_DASHBOARD_USERNAME`/`HERMES_DASHBOARD_PASSWORD` (unset = legacy behavior)
- tests: reachable-vs-authenticated split, cookie login success/reuse/reject,
  gateway fallback, and response-shape normalization
@SherubabaFBC
SherubabaFBC requested a review from outsourc-e as a code owner July 6, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant