hermes-agent/hermes_cli/dashboard_auth
Ben f5ecbe1ec6 feat(dashboard): auto-initiate portal SSO redirect on unauthenticated load
When the dashboard gateway has no local session cookie, it rendered a
click-through /login interstitial — even though the Nous portal's
/oauth/authorize auto-approves any current member of the dashboard's org
and is a silent 302 when the user already holds a portal session. For the
common case (clicking a hosted-agent dashboard link while signed in to the
portal) that interstitial click is pure friction.

This makes the gate auto-initiate the OAuth redirect on an unauthenticated
HTML document load instead of rendering the interstitial, when exactly one
interactive provider is registered. A one-shot loop-guard cookie
(hermes_sso_attempt, 60s TTL) ensures that a genuinely absent portal
session (the portal bounces back still-unauthenticated) falls back to the
/login page after exactly one bounce rather than ping-ponging forever. The
marker is cleared on a successful callback and whenever the gate falls back
to /login.

Security: this removes a human CLICK, not a security check. The redirect
lands on the existing /auth/login route and runs the unchanged PKCE
auth-code flow; token verification, audience checks, redirect-URI match,
and org-membership checks are all untouched. /api/* fetches still get the
401 JSON envelope (never a 302 a fetch() would follow opaquely), and with
two or more providers the /login chooser still renders.

Phase 1 of the cloud-auto-discovery work.
2026-06-29 04:25:18 -07:00
..
__init__.py fix(dashboard-auth): exclude non-interactive providers from interactive login surfaces (#53239) 2026-06-27 10:08:13 +10:00
audit.py feat(dashboard-auth): generic non-interactive API-token capability 2026-06-26 00:47:19 -07:00
base.py fix(dashboard-auth): exclude non-interactive providers from interactive login surfaces (#53239) 2026-06-27 10:08:13 +10:00
cookies.py feat(dashboard): auto-initiate portal SSO redirect on unauthenticated load 2026-06-29 04:25:18 -07:00
login_page.py fix(dashboard-auth): exclude non-interactive providers from interactive login surfaces (#53239) 2026-06-27 10:08:13 +10:00
middleware.py feat(dashboard): auto-initiate portal SSO redirect on unauthenticated load 2026-06-29 04:25:18 -07:00
prefix.py fix(dashboard-auth): warn when public_url override is silently rejected (#43214) 2026-06-10 12:14:57 +10:00
public_paths.py fix(cron): serve /api/cron/fire on the dashboard app (hosted-agent surface) 2026-06-19 12:43:30 +10:00
registry.py fix(dashboard-auth): exclude non-interactive providers from interactive login surfaces (#53239) 2026-06-27 10:08:13 +10:00
routes.py feat(dashboard): auto-initiate portal SSO redirect on unauthenticated load 2026-06-29 04:25:18 -07:00
token_auth.py feat(dashboard-auth): generic non-interactive API-token capability 2026-06-26 00:47:19 -07:00
ws_tickets.py test(dashboard): direct unit coverage for internal WS credential + docstring fix 2026-06-02 23:43:27 -07:00