Skip to content

[Bug]: Dashboard logout revokes tokens but never ends the OIDC session — user is silently re-authenticated, cannot switch accounts #82050

Description

@reshadd94

Bug Description

Summary

With the self_hosted OIDC provider, logging out of the dashboard does not end the session at the identity provider. The user is silently signed back in on the next page view, and switching accounts is impossible without manually clearing the IdP session.

revoke_session() calls the RFC 7009 revocation endpoint with the refresh token. It never calls the provider's end_session_endpoint (RP-initiated logout), even though the discovery document advertises one.

With Keycloak — and any IdP that keeps one SSO session per browser with a client session per application — revoking the refresh token removes only this application's client session. The SSO session survives as long as any other application is attached to it. The dashboard's silent SSO attempt then immediately re-authenticates the same user.

Why this is easy to miss

The bug is intermittent in a way that misleads: if the dashboard happens to be the only application attached to the SSO session, revocation removes the last client session, the IdP drops the SSO session as well, and logout appears to work correctly. It only fails once a second application in the same realm is also signed in.

Verified against the IdP in our deployment — one SSO session, two client sessions:

GET /admin/realms/<realm>/users/<uid>/sessions
→ 1 session, clients: ['<other-app-client-id>', '<hermes-client-id>']

A further consequence of the same root cause: two Hermes containers sharing one /opt/data and served under two different hostnames (hermes serve and hermes dashboard) share the IdP session. Signing in on one changes the identity shown by the other.

Relevant code

plugins/dashboard_auth/self_hosted/__init__.py, revoke_session():

endpoint = str(disco.get("revocation_endpoint") or "").strip()
if not endpoint:
    return None
...
httpx.post(endpoint, data=data, headers=headers, timeout=_TOKEN_ENDPOINT_TIMEOUT_SEC)

hermes_cli/dashboard_auth/routes.py, auth_logout() — revokes and clears cookies; no IdP redirect.

Suggested fix

After the local cleanup, redirect the browser to the provider's end_session_endpoint when discovery advertises one:

{end_session_endpoint}?id_token_hint=<id_token>&post_logout_redirect_uri=<dashboard public url>

client_id works as an alternative to id_token_hint where no ID token is retained. Token revocation is worth keeping — the two are complementary: revocation invalidates the tokens, RP-initiated logout ends the session.

Two details from deploying this:

  • The public URL should come from the existing HERMES_DASHBOARD_PUBLIC_URL / dashboard.public_url resolution, so the post-logout redirect is correct behind a reverse proxy.
  • IdPs validate post_logout_redirect_uri against a separate allow-list (Keycloak: the client attribute post.logout.redirect.uris), not against the redirect URIs. Worth a line in the docs — it is an easy misconfiguration.

Secondary observation (lower severity)

revoke_session() is best-effort and swallows every failure at debug level, while the cookies are cleared regardless. A failed revocation is therefore indistinguishable from a successful logout for the user. A warning-level log would have shortened our diagnosis considerably.

Steps to Reproduce

  1. Configure dashboard.oauth.self_hosted against an IdP that maintains an SSO session (Keycloak 26.1 here) and register a second OIDC client in the same realm for any other application.
  2. Sign in to the other application in the same browser.
  3. Sign in to the Hermes dashboard as the same user.
  4. Click logout in the dashboard.
  5. Load any dashboard page again.

Expected: the login screen; a different account can be chosen.
Actual: signed in again as the same user, without a prompt. Clearing browser cookies does not help — the IdP session is still valid, so the next silent attempt succeeds again.

Expected Behavior

  • Logout does not maintain SSO session and therefore does not recreate the access

Actual Behavior

  • Logout maintains SSO session and therefore recreated the hermes dashboard session automatically

Affected Component

Gateway (Telegram/Discord/Slack/WhatsApp)

Messaging Platform (if gateway-related)

No response

Debug Report

none

Operating System

Ubuntu 24.04

Python Version

No response

Hermes Version

No response

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low — cosmetic, nice to havearea/authAuthentication, OAuth, credential poolsbugcomp/dashboardWeb dashboard / control panel UI (dashboard/, landing)comp/pluginsPlugin system and bundled pluginsduplicateThis issue or pull request already existssweeper:risk-security-boundarySweeper risk: may affect sandboxing, auth, credentials, or sensitive datatype/featureNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions