Environment
- Dashboard:
netbirdio/dashboard:latest (v2.36.0 at time of report)
- Server:
netbirdio/netbird:latest combined image, v0.69.0
- IdP topology: embedded Dex federated (OIDC connector) to an external IdP (Authentik 2026.2.1)
- Auth config:
AUTH_AUTHORITY=https://<host>/oauth2 (Dex), USE_AUTH0=false
Summary
Clicking Logout in the dashboard clears local OIDC tokens client-side but never initiates RP-initiated logout against the configured authority. Because silent_renew / silent auth is still active, the SPA immediately re-authenticates against Dex (which still has a valid session cookie) and the user is returned to the dashboard as if nothing happened.
Steps to reproduce
- Sign in to the dashboard via an external IdP federated through the embedded Dex.
- Click the user menu → Logout.
- Observe: the page briefly flickers, then lands back at the dashboard, still authenticated.
What I found in the built bundle
In chunk bda14900bb28840a.js the OIDC config builder computes:
end_session_endpoint: new URL("v2/logout", I.authority).href
…but the actual Logout handler is:
logout: async () => t("/", { client_id: d.clientId })
It clears tokens and navigates to /. It never navigates to end_session_endpoint, never passes id_token_hint, and never sets post_logout_redirect_uri. The computed end-session URL is unused.
Expected behavior
Logout should perform RP-initiated logout per the OIDC spec:
GET {end_session_endpoint}?id_token_hint={last_id_token}&post_logout_redirect_uri={dashboard_origin}&client_id={client_id}
so the upstream (Dex, and transitively the federated IdP) can terminate the session.
Suggested fix
Either:
- (a) Have the Logout handler navigate to the computed
end_session_endpoint with id_token_hint + post_logout_redirect_uri; fall back to {authority}/v2/logout when the discovery doc doesn't advertise one.
- (b) Add an optional
AUTH_END_SESSION_URL env var (parallel to AUTH_AUTHORITY) so operators with external IdPs can point logout directly at the upstream end_session_endpoint, bypassing Dex.
Impact
Any self-hosted Netbird deployment where the embedded Dex federates to an external IdP: Logout is effectively a no-op as long as the upstream SSO cookie survives. Workarounds (JS shim, Traefik redirect on /v2/logout) exist but are fragile.
Environment
netbirdio/dashboard:latest(v2.36.0 at time of report)netbirdio/netbird:latestcombined image, v0.69.0AUTH_AUTHORITY=https://<host>/oauth2(Dex),USE_AUTH0=falseSummary
Clicking Logout in the dashboard clears local OIDC tokens client-side but never initiates RP-initiated logout against the configured authority. Because
silent_renew/ silent auth is still active, the SPA immediately re-authenticates against Dex (which still has a valid session cookie) and the user is returned to the dashboard as if nothing happened.Steps to reproduce
What I found in the built bundle
In chunk
bda14900bb28840a.jsthe OIDC config builder computes:…but the actual Logout handler is:
It clears tokens and navigates to
/. It never navigates toend_session_endpoint, never passesid_token_hint, and never setspost_logout_redirect_uri. The computed end-session URL is unused.Expected behavior
Logout should perform RP-initiated logout per the OIDC spec:
so the upstream (Dex, and transitively the federated IdP) can terminate the session.
Suggested fix
Either:
end_session_endpointwithid_token_hint+post_logout_redirect_uri; fall back to{authority}/v2/logoutwhen the discovery doc doesn't advertise one.AUTH_END_SESSION_URLenv var (parallel toAUTH_AUTHORITY) so operators with external IdPs can point logout directly at the upstreamend_session_endpoint, bypassing Dex.Impact
Any self-hosted Netbird deployment where the embedded Dex federates to an external IdP: Logout is effectively a no-op as long as the upstream SSO cookie survives. Workarounds (JS shim, Traefik redirect on
/v2/logout) exist but are fragile.