fix(dashboard): chat tab works in gated (OAuth) mode (#34793)

The Chat/TUI dashboard tab showed a false "Session token unavailable"
error and never rendered the terminal whenever the dashboard ran in
gated mode (OAuth auth gate active, --insecure not set), even though
the user was fully authenticated and every other tab worked.

Two checks in ChatPage.tsx gated purely on window.__HERMES_SESSION_TOKEN__,
which the server intentionally omits in gated mode (web_server.py only
injects __HERMES_AUTH_REQUIRED__=true there; the SPA is expected to use
cookie auth + a single-use WS ticket). buildWsAuthParam() already resolves
WS auth correctly for both modes, but the early bail prevented the effect
from ever reaching it.

Both checks now also honor __HERMES_AUTH_REQUIRED__: the banner no longer
fires and the xterm/WS effect no longer bails in gated mode.

Reported-by: wbrione <wbrione@users.noreply.github.com>
Closes #34755
This commit is contained in:
Teknium
2026-05-29 12:19:51 -07:00
committed by GitHub
parent 90b3c54de9
commit 1596bb287e

View File

@ -119,8 +119,13 @@ export default function ChatPage({ isActive = true }: { isActive?: boolean }) {
const [searchParams, setSearchParams] = useSearchParams();
// Lazy-init: the missing-token check happens at construction so the effect
// body doesn't have to setState (React 19's set-state-in-effect rule).
// In gated (OAuth) mode the server intentionally omits the session token —
// the SPA authenticates the WS via a single-use ticket (buildWsAuthParam),
// so a missing token there is expected, not an error.
const [banner, setBanner] = useState<string | null>(() =>
typeof window !== "undefined" && !window.__HERMES_SESSION_TOKEN__
typeof window !== "undefined" &&
!window.__HERMES_SESSION_TOKEN__ &&
!window.__HERMES_AUTH_REQUIRED__
? "Session token unavailable. Open this page through `hermes dashboard`, not directly."
: null,
);
@ -273,8 +278,11 @@ export default function ChatPage({ isActive = true }: { isActive?: boolean }) {
if (!host) return;
const token = window.__HERMES_SESSION_TOKEN__;
const gated = !!window.__HERMES_AUTH_REQUIRED__;
// Banner already initialised above; just bail before wiring xterm/WS.
if (!token) {
// In gated mode the token is absent by design — buildWsAuthParam() mints
// a WS ticket instead, so don't bail; let the effect reach that path.
if (!token && !gated) {
return;
}
@ -876,5 +884,6 @@ export default function ChatPage({ isActive = true }: { isActive?: boolean }) {
declare global {
interface Window {
__HERMES_SESSION_TOKEN__?: string;
__HERMES_AUTH_REQUIRED__?: boolean;
}
}