Summary
When the admin panel is configured for SSO (ADMIN_SSO_ONLY=true) against an OpenID provider that uses RP-initiated logout (OPENID_USE_END_SESSION_ENDPOINT=true on the LibreChat server), the Sign out button never actually signs you out. Clicking it clears the local session, returns to /login, and the page immediately auto-redirects back to the IdP — which still has a live session — silently re-authenticating the same account. The user can never sign out or switch accounts: a sign-out loop.
Root cause
adminLogoutFn in src/server/auth.ts POSTs to LibreChat's /api/auth/logout but ignores the response body:
await fetch(`${getServerApiUrl()}/api/auth/logout`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` },
});
// response discarded
With OPENID_USE_END_SESSION_ENDPOINT=true, LibreChat's logoutController returns the IdP end_session URL in the JSON response as { redirect }. Because the admin panel discards the response, only the local cookie is cleared and the IdP session survives. Sidebar.handleLogout then navigates to /login, and with ADMIN_SSO_ONLY=true the login page auto-redirects to the IdP, which silently re-authenticates.
LibreChat's own web client avoids this: its AuthContext logout handler reads data.redirect and follows it via window.location. The admin panel just needs to do the same.
Steps to reproduce
- Configure LibreChat with OpenID and
OPENID_USE_END_SESSION_ENDPOINT=true.
- Run the admin panel with
ADMIN_SSO_ONLY=true.
- Sign into the admin panel via SSO.
- Click Sign out.
Expected: The IdP session is terminated; you land on the login page (or the IdP account picker) and can sign in as a different account.
Actual: You are silently signed back into the same account.
Suggested fix
Parse the logout response in adminLogoutFn and surface redirect; have Sidebar.handleLogout follow it via window.location when present, falling back to the existing /login navigation otherwise. PR follows.
Summary
When the admin panel is configured for SSO (
ADMIN_SSO_ONLY=true) against an OpenID provider that uses RP-initiated logout (OPENID_USE_END_SESSION_ENDPOINT=trueon the LibreChat server), the Sign out button never actually signs you out. Clicking it clears the local session, returns to/login, and the page immediately auto-redirects back to the IdP — which still has a live session — silently re-authenticating the same account. The user can never sign out or switch accounts: a sign-out loop.Root cause
adminLogoutFninsrc/server/auth.tsPOSTs to LibreChat's/api/auth/logoutbut ignores the response body:With
OPENID_USE_END_SESSION_ENDPOINT=true, LibreChat'slogoutControllerreturns the IdPend_sessionURL in the JSON response as{ redirect }. Because the admin panel discards the response, only the local cookie is cleared and the IdP session survives.Sidebar.handleLogoutthen navigates to/login, and withADMIN_SSO_ONLY=truethe login page auto-redirects to the IdP, which silently re-authenticates.LibreChat's own web client avoids this: its
AuthContextlogout handler readsdata.redirectand follows it viawindow.location. The admin panel just needs to do the same.Steps to reproduce
OPENID_USE_END_SESSION_ENDPOINT=true.ADMIN_SSO_ONLY=true.Expected: The IdP session is terminated; you land on the login page (or the IdP account picker) and can sign in as a different account.
Actual: You are silently signed back into the same account.
Suggested fix
Parse the logout response in
adminLogoutFnand surfaceredirect; haveSidebar.handleLogoutfollow it viawindow.locationwhen present, falling back to the existing/loginnavigation otherwise. PR follows.