* 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>
* create data-provider package and move code from data-provider folder to be shared between apps
* fix type issues
* add packages to ignore
* add new data-provider package to apps
* refactor: change client imports to use @librechat/data-provider package
* include data-provider build script in frontend build
* fix type issue after rebasing
* delete admin/package.json from this branch
* update test ci script to include building of data-provider package
* Try using regular build for test action
* Switch frontend-review back to build:ci
* Remove loginRedirect from Login.tsx
* Add ChatGPT back to EModelEndpoint
2023-07-04 15:47:41 -04:00
Renamed from client/src/data-provider/headers-helpers.ts (Browse further)