fix(ui): proper OIDC logout — server revoke + top-level redirect

Previous logout fired fetch(end_session, {mode:'no-cors'}), which is a
no-op for OIDC: cross-origin fetch never clears the IdP's session cookie.
Result: subsequent SSO clicks silently re-authenticated the prior user.

New flow:
1. Best-effort POST /auth/logout to bump token_revoked_before.
2. Clear localStorage + Zustand state.
3. Set sessionStorage 'cameleer:signed_out=1' so /login renders a
   confirmation splash (mirrors cameleer-saas pattern).
4. window.location.replace(end_session_endpoint?id_token_hint=...
   &post_logout_redirect_uri=...&client_id=...) — top-level navigation,
   the only form that actually clears the IdP session cookie.

client_id is now persisted at OIDC initiation alongside
end_session_endpoint and id_token, so logout has all three params
without an extra round-trip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-27 11:57:04 +02:00
parent da3895c31d
commit 82e2593332
2 changed files with 31 additions and 7 deletions

View File

@@ -77,6 +77,9 @@ export function LoginPage() {
if (data.endSessionEndpoint) {
localStorage.setItem('cameleer-oidc-end-session', data.endSessionEndpoint);
}
if (data.clientId) {
localStorage.setItem('cameleer-oidc-client-id', data.clientId);
}
const redirectUri = `${window.location.origin}${config.basePath}oidc/callback`;
const scopes = ['openid', 'email', 'profile', ...PLATFORM_SCOPES, ...(data.additionalScopes || [])];
const params = new URLSearchParams({