hermes - 💡(How to fix) Fix [Bug]: Chat tab unusable in gated (OAuth) mode — "Session token unavailable" false positive [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When the dashboard runs in gated mode (OAuth auth gate active, --insecure not set), the Chat/TUI tab shows a false error:

Session token unavailable. Open this page through hermes dashboard, not directly.

The tab never renders the terminal, even though the user is fully authenticated via OAuth and all other dashboard features (config, sessions, events feed sidebar) work correctly.

Error Message

When the dashboard runs in gated mode (OAuth auth gate active, --insecure not set), the Chat/TUI tab shows a false error:

Root Cause

Two checks in ChatPage.tsx gate on window.__HERMES_SESSION_TOKEN__, which is intentionally not injected in gated mode. The server-side _serve_index() (web_server.py ~line 3856) skips the token injection when app.state.auth_required is true — the SPA is expected to use cookie auth + POST /api/auth/ws-ticket instead.

Check 1 — Banner initialization (line 122-125):

const [banner, setBanner] = useState<string | null>(() =>
  typeof window !== "undefined" && !window.__HERMES_SESSION_TOKEN__
    ? "Session token unavailable. Open this page through `hermes dashboard`, not directly."
    : null,
);

Check 2 — xterm/WS effect bail (line 275-278):

const token = window.__HERMES_SESSION_TOKEN__;
// Banner already initialised above; just bail before wiring xterm/WS.
if (!token) {
  return;
}

In gated mode, neither check considers window.__HERMES_AUTH_REQUIRED__ (which IS injected by the server). The WS connection code at ~line 560 already uses buildWsAuthParam() which handles gated mode correctly via getWsTicket(), but the early bail at line 278 prevents the code from ever reaching that path.

Fix Action

Fixed

Code Example

const [banner, setBanner] = useState<string | null>(() =>
  typeof window !== "undefined" && !window.__HERMES_SESSION_TOKEN__
    ? "Session token unavailable. Open this page through `hermes dashboard`, not directly."
    : null,
);

---

const token = window.__HERMES_SESSION_TOKEN__;
// Banner already initialised above; just bail before wiring xterm/WS.
if (!token) {
  return;
}

---

const [banner, setBanner] = useState<string | null>(() =>
  typeof window !== "undefined" &&
  !window.__HERMES_SESSION_TOKEN__ &&
  !window.__HERMES_AUTH_REQUIRED__
    ? "Session token unavailable. Open this page through `hermes dashboard`, not directly."
    : null,
);

---

const token = window.__HERMES_SESSION_TOKEN__;
const gated = !!window.__HERMES_AUTH_REQUIRED__;
if (!token && !gated) {
  return;
}
RAW_BUFFERClick to expand / collapse

Description

When the dashboard runs in gated mode (OAuth auth gate active, --insecure not set), the Chat/TUI tab shows a false error:

Session token unavailable. Open this page through hermes dashboard, not directly.

The tab never renders the terminal, even though the user is fully authenticated via OAuth and all other dashboard features (config, sessions, events feed sidebar) work correctly.

Root Cause

Two checks in ChatPage.tsx gate on window.__HERMES_SESSION_TOKEN__, which is intentionally not injected in gated mode. The server-side _serve_index() (web_server.py ~line 3856) skips the token injection when app.state.auth_required is true — the SPA is expected to use cookie auth + POST /api/auth/ws-ticket instead.

Check 1 — Banner initialization (line 122-125):

const [banner, setBanner] = useState<string | null>(() =>
  typeof window !== "undefined" && !window.__HERMES_SESSION_TOKEN__
    ? "Session token unavailable. Open this page through `hermes dashboard`, not directly."
    : null,
);

Check 2 — xterm/WS effect bail (line 275-278):

const token = window.__HERMES_SESSION_TOKEN__;
// Banner already initialised above; just bail before wiring xterm/WS.
if (!token) {
  return;
}

In gated mode, neither check considers window.__HERMES_AUTH_REQUIRED__ (which IS injected by the server). The WS connection code at ~line 560 already uses buildWsAuthParam() which handles gated mode correctly via getWsTicket(), but the early bail at line 278 prevents the code from ever reaching that path.

Affected Deployments

Any dashboard running in gated mode, regardless of the OAuth provider:

  • Self-hosted Authentik (OIDC)
  • Nous Portal OAuth
  • Any custom DashboardAuthProvider plugin

Related: #15731 (same symptom in --insecure mode, different root cause — loopback WS rejection vs. client-side false bail).

Suggested Fix

Two-line change in ChatPage.tsx:

Check 1 — also allow gated mode:

const [banner, setBanner] = useState<string | null>(() =>
  typeof window !== "undefined" &&
  !window.__HERMES_SESSION_TOKEN__ &&
  !window.__HERMES_AUTH_REQUIRED__
    ? "Session token unavailable. Open this page through `hermes dashboard`, not directly."
    : null,
);

Check 2 — don't bail in gated mode:

const token = window.__HERMES_SESSION_TOKEN__;
const gated = !!window.__HERMES_AUTH_REQUIRED__;
if (!token && !gated) {
  return;
}

The existing buildWsAuthParam() in api.ts already resolves WS auth correctly for both modes. This fix simply removes the premature bail that prevents the code from reaching it.

Verification

Tested this exact fix on a self-hosted deployment (Hermes v0.15.x behind reverse proxy + OIDC). After applying the two changes and rebuilding the SPA:

  • ✅ Chat tab renders the terminal and connects via ?ticket= auth
  • ✅ Events feed sidebar shows "live" status
  • ✅ Login/logout flow works correctly
  • ✅ Loopback mode (--insecure) unaffected — __HERMES_SESSION_TOKEN__ is still injected and used as before

Environment

  • Hermes Agent v0.15.x
  • Dashboard: --host 0.0.0.0 (gated mode, no --insecure)
  • Access: reverse proxy (HTTPS) → dashboard (HTTP)

Additional Context

This issue was identified and the fix was verified by an AI assistant (Hermes Agent) under human supervision. The diagnosis and proposed fix were reviewed by the system administrator before submission.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix [Bug]: Chat tab unusable in gated (OAuth) mode — "Session token unavailable" false positive [1 pull requests]