"use client"; import { useEffect } from "react"; import { signOut, useSession } from "next-auth/react"; import { clearAuthCookies, clearKeycloakCookies } from "@/lib/session"; export function SignOutHandler() { const { data: session } = useSession(); useEffect(() => { const handleSignOut = async () => { try { // Mark that we're logging out to prevent auto-login and refresh attempts sessionStorage.setItem('just_logged_out', 'true'); // Also set a cookie flag that persists across redirects document.cookie = 'logout_in_progress=true; path=/; max-age=60'; // 60 seconds // Get Keycloak issuer from environment const keycloakIssuer = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER; const idToken = session?.idToken; // Clear NextAuth cookies immediately before signOut clearAuthCookies(); // Also attempt to clear Keycloak cookies clearKeycloakCookies(); // End SSO session using Admin API before signing out // This ensures the realm-wide SSO session is cleared, // not just the client session try { const ssoLogoutResponse = await fetch('/api/auth/end-sso-session', { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', }, }); if (ssoLogoutResponse.ok) { console.log('SSO session ended successfully'); } else { const errorData = await ssoLogoutResponse.json().catch(() => ({})); console.warn('Failed to end SSO session via Admin API, continuing with standard logout:', errorData); // Continue with logout even if SSO session termination fails } } catch (error) { console.error('Error ending SSO session:', error); // Continue with logout even if SSO session termination fails } // Sign out from NextAuth (clears NextAuth session) await signOut({ callbackUrl: "/signin?logout=true", redirect: false }); // If we have Keycloak ID token and issuer, call Keycloak logout if (keycloakIssuer && idToken) { const keycloakLogoutUrl = new URL( `${keycloakIssuer}/protocol/openid-connect/logout` ); // Add required parameters - include logout=true in redirect URI keycloakLogoutUrl.searchParams.append( 'post_logout_redirect_uri', window.location.origin + '/signin?logout=true' ); keycloakLogoutUrl.searchParams.append( 'id_token_hint', idToken ); // Add kc_action=LOGOUT to ensure SSO session is cleared keycloakLogoutUrl.searchParams.append( 'kc_action', 'LOGOUT' ); // Immediate redirect to Keycloak logout (prevents widget rendering) window.location.replace(keycloakLogoutUrl.toString()); } else { // Fallback: just redirect to signin if we don't have Keycloak info window.location.replace('/signin?logout=true'); } } catch (error) { console.error('Error during sign out:', error); // Fallback: redirect to signin on error window.location.replace('/signin?logout=true'); } }; handleSignOut(); }, [session]); return null; }