NeahNew/components/auth/signout-handler.tsx

95 lines
3.4 KiB
TypeScript

"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;
}