Skip to content

[Bug]: Dashboard auto-SSO redirect 500s when only basic auth provider is configured #58237

Description

@robertsmieja

Bug Description

When the Hermes Dashboard is bound to 0.0.0.0 (non-loopback) with only basic_auth configured, visiting the root URL redirects to /auth/login?provider=basic which calls start_login() — but the basic auth provider is password-only and raises NotImplementedError, resulting in a 500 Internal Server Error.

This breaks a documented and recommended configuration path: basic auth is listed as one of three bundled auth methods and is the recommended "zero-infra" way to secure the dashboard on a trusted LAN (see Web Dashboard docs).

Steps to Reproduce

  1. Configure basic auth in config.yaml:
    dashboard:
      basic_auth:
        username: admin
        password_hash: "<scrypt hash>"
  2. Start the dashboard on a non-loopback address:
    hermes dashboard --host 0.0.0.0 --port 9119
    
  3. Visit http://<host>:9119/ in a browser
  4. Observe 500 Internal Server Error

Expected Behavior

Visiting http://<host>:9119/ should redirect to /login (the password form page), where the user can enter credentials and POST to /auth/password-login.

Actual Behavior

The browser receives a 302 Found to /auth/login?provider=basic&next=%2F, which then returns 500 Internal Server Error with:

NotImplementedError: BasicAuthProvider is password-only; there is no OAuth redirect flow. The login page POSTs to /auth/password-login instead.

Affected Component

Dashboard / Auth

Messaging Platform

N/A (CLI only)

Debug Report

version:          0.18.0 [09693cd3] (2026-07-04)
os:               Linux 6.18.35 x86_64 (NixOS 26.05)
python:           3.11.15
openai_sdk:       2.24.0

Operating System

NixOS 26.05

Python Version

3.11.15 (Hermes venv) / 3.13.13 (system)

Hermes Version

v0.18.0 (09693cd)

Additional Logs / Traceback

Full traceback from journal:

  File "hermes_cli/dashboard_auth/routes.py", line 197, in auth_login
    ls = p.start_login(redirect_uri=_redirect_uri(request))
  File "plugins/dashboard_auth/basic/__init__.py", line 230, in start_login
    raise NotImplementedError(
NotImplementedError: BasicAuthProvider is password-only; there is no OAuth redirect flow. The login page POSTs to /auth/password-login instead.

Root Cause Analysis

The issue is in _auto_sso_response() in hermes_cli/dashboard_auth/middleware.py. When a user visits the dashboard root without a session cookie, the middleware tries to auto-initiate an SSO redirect:

providers = list_session_providers()
if len(providers) != 1:
    return None

provider = providers[0]
auth_login = f"{prefix}/auth/login?provider={quote(provider.name, safe='')}"
return RedirectResponse(url=auth_login, status_code=302)

list_session_providers() filters on supports_session=True, which includes the basic auth provider (it has supports_session=True, supports_password=True). With basic auth as the only registered provider, the middleware auto-redirects to /auth/login?provider=basic — the OAuth redirect flow. But basic auth's start_login() is a stub that raises NotImplementedError (it implements complete_password_login instead).

The password-only property already exists on the provider base class (DashboardAuthProvider.supports_password), but _auto_sso_response doesn't check it.

Proposed Fix

Filter out password-only providers from the auto-SSO provider list, since they cannot initiate an OAuth redirect:

# In _auto_sso_response, replace:
providers = list_session_providers()

# With:
providers = [
    p for p in list_session_providers()
    if not p.supports_password
]

When password-only providers are filtered out and count reaches zero, _auto_sso_response returns None, and the middleware falls through to the ordinary _unauth_response which correctly redirects to /login (the password form page).

Note: _unauth_response already does the right thing — it redirects HTML navigation to /login and returns 401 JSON with login_url for API routes. Only the auto-SSO fast-path has this bug.

Upstream context

The _auto_sso_response function was added in commit f5ecbe1ec (feat(dashboard): auto-initiate portal SSO redirect). It was originally guarded by an _interactive_providers() helper (commit dbe734bef excluded non-session providers), but that helper was later inlined in commit 61f56d27d as list_session_providers() because the supports_session filter was already handled by the registry function. Neither change accounted for password-only (non-OAuth) session providers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/authAuthentication, OAuth, credential poolscomp/dashboardWeb dashboard / control panel UI (dashboard/, landing)duplicateThis issue or pull request already existssweeper:implemented-on-mainSweeper: behavior already present on current maintype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions