Skip to content

fix(auth): prevent redirects from interrupting OIDC logout - #292

Merged
cxymds merged 2 commits into
mainfrom
cxymds/fix-oidc-logout-race
Nov 10, 2026
Merged

cxymds merged 2 commits into
mainfrom
cxymds/fix-oidc-logout-race

Conversation

@cxymds

@cxymds cxymds commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Pull Request

Description

Clearing Console credentials during OIDC logout triggers dashboard and stale API/S3 error callbacks that can redirect to the login page before the pending logout navigation reaches the IdP. Guard those automatic redirects with a synchronous logout flag set before the first await, so local credentials can still be cleared while the browser follows the backend-to-IdP redirect chain.

Prevent duplicate logout attempts, retain the existing fallback when logout cannot start, and add a keyboard-accessible Back to Login link for interrupted navigation. Restore normal logout and authentication redirects when another tab signs in after an interrupted logout, without releasing protection for repeated credentials events during logout. Recover a dashboard restored from the back-forward cache without deleting a newer session established in another document.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test improvements
  • Security fix

Testing

  • Unit tests added/updated
  • Manual testing completed

Replaced the source-pattern logout test with 24 React behavior tests covering redirect races, stale API/S3 callbacks, duplicate logout, fallback errors, credential cleanup, recovery links, and back-forward cache restoration.

All checks passed with Node.js 22:

pnpm install --frozen-lockfile
pnpm type-check
pnpm lint
pnpm format:check
pnpm test:run  # 946 passed, 0 failed

Chrome validation with a local mock backend and IdP:

  • A delayed backend 302 followed by an IdP 302 completed at the login page without cancelling the logout request; all three auth storage entries were cleared.
  • After deliberately stopping the pending navigation, Back to Login remained available and worked with Enter.
  • The recovery state had no horizontal overflow at 390px in dark mode, with a 44px link target.

Checklist

  • Code follows the project's style guidelines
  • Self-review completed
  • TypeScript types are properly defined
  • All commit messages are in English (Conventional Commits)
  • All existing tests pass
  • No new dependencies added, or they are justified

Related Issues

Closes #289

Screenshots (if applicable)

The pair below shows the state after deliberately cancelling a slow logout navigation. Before, the client redirects to login; after, the recovery link remains available without an automatic redirect taking over.

Before After
Before: login after cancelled logout After: recovery link after cancelled logout

Mobile dark mode recovery state:

Recovery link at 390px in dark mode

Additional Notes

Browser validation used a local mock IdP; real Keycloak integration has not been run. The screenshots demonstrate interrupted-navigation recovery, while the redirect race is covered by the behavior tests.

Keep federated logout in progress until its full-page navigation completes so dashboard guards and stale API or S3 errors cannot cancel the IdP redirect. Add behavioral regression coverage and a recovery link for cancelled navigation.
Copilot AI balanced review requested due to automatic review settings November 10, 2026 02:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A new session received through cross-tab storage events leaves the logout flag set, preventing subsequent logout and keeping API/S3 authentication redirects disabled.

1 open issue
What changed in this PR

Addresses #289 by preventing automatic Console redirects from interrupting OIDC logout before the browser reaches the identity provider.

Changes:

  • Adds a synchronous logout flag to suppress dashboard and API/S3 redirects and prevent duplicate logout attempts.
  • Adds a Back to Login recovery link and back-forward cache recovery that preserves newer sessions.
  • Replaces source-pattern checks with 19 behavior tests covering logout races, fallbacks, and recovery.
File Description
tests/​lib/​oidc-logout-source.test.js Removes source-pattern logout checks.
tests/​hooks/​use-permissions-refresh.test.ts Updates the auth mock with the logout-state getter.
tests/​hooks/​use-oidc-logout.test.ts Adds logout navigation and recovery behavior tests.
contexts/​s3-context.tsx Suppresses S3 authentication redirects during logout.
contexts/​auth-context.tsx Tracks logout progress, blocks duplicates, and handles cached-page restoration.
contexts/​api-context.tsx Suppresses API error redirects during logout.
components/​dashboard-auth-guard.tsx Guards automatic redirects and adds a login recovery link.

Review effort: Balanced

Comment thread contexts/auth-context.tsx Resolved
Reset logout protection when storage restores an authenticated session before consumer effects handle authentication errors. Keep pending logout protected against repeated credentials events and cover the cross-tab recovery behavior.
@cxymds
cxymds merged commit 9d5b78f into main Nov 10, 2026
9 checks passed
@cxymds
cxymds deleted the cxymds/fix-oidc-logout-race branch November 10, 2026 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OIDC logout still aborted before reaching the IdP in v0.1.37/v0.1.38 (follow-up to #190/#191)

2 participants