LibreChat/client
Danny Avila b18915a96b
🚪 fix: Complete OIDC RP-Initiated Logout With id_token_hint and Redirect Race Fix (#12024)
* fix: complete OIDC logout implementation

The OIDC logout feature added in #5626 was incomplete:

1. Backend: Missing id_token_hint/client_id parameters required by the
   RP-Initiated Logout spec. Keycloak 18+ rejects logout without these.

2. Frontend: The logout redirect URL was passed through isSafeRedirect()
   which rejects all absolute URLs. The redirect was silently dropped.

Backend: Add id_token_hint (preferred) or client_id (fallback) to the
logout URL for OIDC spec compliance.

Frontend: Use window.location.replace() for logout redirects from the
backend, bypassing isSafeRedirect() which was designed for user-input
validation.

Fixes #5506

* fix: accept undefined in setTokenHeader to properly clear Authorization header

When token is undefined, delete the Authorization header instead of
setting it to "Bearer undefined". Removes the @ts-ignore workaround
in AuthContext.

* fix: skip axios 401 refresh when Authorization header is cleared

When the Authorization header has been removed (e.g. during logout),
the response interceptor now skips the token refresh flow. This
prevents a successful refresh from canceling an in-progress OIDC
external redirect via window.location.replace().

* fix: guard against undefined OPENID_CLIENT_ID in logout URL

Prevent literal "client_id=undefined" in the OIDC end-session URL
when OPENID_CLIENT_ID is not set. Log a warning when neither
id_token_hint nor client_id is available.

* fix: prevent race condition canceling OIDC logout redirect

The logout mutation wrapper's cleanup (clearStates, removeQueries)
triggers re-renders and 401s on in-flight requests. The axios
interceptor would refresh the token successfully, firing
dispatchTokenUpdatedEvent which cancels the window.location.replace()
navigation to the IdP's end_session_endpoint.

Fix:
- Clear Authorization header synchronously before redirect so the
  axios interceptor skips refresh for post-logout 401s
- Add isExternalRedirectRef to suppress silentRefresh and useEffect
  side effects during the redirect
- Add JSDoc explaining why isSafeRedirect is bypassed

* test: add LogoutController and AuthContext logout test coverage

LogoutController.spec.js (13 tests):
- id_token_hint from session and cookie fallback
- client_id fallback, including undefined OPENID_CLIENT_ID guard
- Disabled endpoint, missing issuer, non-OpenID user
- post_logout_redirect_uri (custom and default)
- Missing OpenID config and end_session_endpoint
- Error handling and cookie clearing

AuthContext.spec.tsx (3 tests):
- OIDC redirect calls window.location.replace + setTokenHeader
- Non-redirect logout path
- Logout error handling

* test: add coverage for setTokenHeader, axios interceptor guard, and silentRefresh suppression

headers-helpers.spec.ts (3 tests):
- Sets Authorization header with Bearer token
- Deletes Authorization header when called with undefined
- No-op when clearing an already absent header

request-interceptor.spec.ts (2 tests):
- Skips refresh when Authorization header is cleared (the race fix)
- Attempts refresh when Authorization header is present

AuthContext.spec.tsx (1 new test):
- Verifies silentRefresh is not triggered after OIDC redirect

* test: enhance request-interceptor tests with adapter restoration and refresh verification

- Store the original axios adapter before tests and restore it after all tests to prevent side effects.
- Add verification for the refresh endpoint call in the interceptor tests to ensure correct behavior during token refresh attempts.

* test: enhance AuthContext tests with live rendering and improved logout error handling

- Introduced a new `renderProviderLive` function to facilitate testing with silentRefresh.
- Updated tests to use the live rendering function, ensuring accurate simulation of authentication behavior.
- Enhanced logout error handling test to verify that auth state is cleared without external redirects.

* test: update LogoutController tests for OpenID config error handling

- Renamed test suite to clarify that it handles cases when OpenID config is not available.
- Modified test to check for error thrown by getOpenIdConfig instead of returning null, ensuring proper logging of the error message.

* refactor: improve OpenID config error handling in LogoutController

- Simplified error handling for OpenID configuration retrieval by using a try-catch block.
- Updated logging to provide clearer messages when the OpenID config is unavailable.
- Ensured that the end session endpoint is only accessed if the OpenID config is successfully retrieved.

---------

Co-authored-by: cloudspinner <stijn.tastenhoye@gmail.com>
2026-03-02 21:34:13 -05:00
..
public 🎭 chore: Padding to Maskable Icon for Android adaptive icons (#11626) 2026-02-04 15:51:51 +01:00
scripts 🔧 refactor: Build Process and Static Asset Handling (#7605) 2025-05-28 11:48:04 -04:00
src 🚪 fix: Complete OIDC RP-Initiated Logout With id_token_hint and Redirect Race Fix (#12024) 2026-03-02 21:34:13 -05:00
test 🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804) 2025-08-13 16:24:17 -04:00
babel.config.cjs chore: Remove Unused Dependencies 🧹 (#939) 2023-09-14 15:12:22 -04:00
check_updates.sh 🔧 fix: Resolve Proper Dependencies to fix Application Error (#2488) 2024-04-22 12:52:30 -04:00
index.html 🌐 feat: Add support to SubDirectory hosting (#9155) 2025-08-27 02:00:18 -04:00
jest.config.cjs v0.8.3-rc1 (#11856) 2026-02-18 20:36:03 -05:00
nginx.conf 🚅 chore: Added an Example of Nginx gzip Settings (#3173) 2024-06-23 13:49:00 -04:00
package.json 🛡️ chore: Bump ESLint Tooling Deps and Resolve ajv Security Vulnerability (#11938) 2026-02-24 21:30:28 -05:00
postcss.config.cjs refactor: Settings/Presets UI Restructure, convert many files to TS (#740) 2023-08-04 13:56:44 -04:00
tailwind.config.cjs style(MCP): Enhance dialog accessibility and styling consistency (#11585) 2026-02-11 22:08:40 -05:00
tsconfig.json 🖼️ style: Improve Marketplace & Sharing Dialog UI 2025-08-13 16:24:24 -04:00
vite.config.ts 🧩 fix: Redirect Stability and Build Chunking (#11965) 2026-02-26 16:43:24 -05:00