"use client"; import { useEffect } from "react"; import { useSession, signOut } from "next-auth/react"; import { clearAuthCookies } from "@/lib/session"; export function SignOutHandler() { const { data: session } = useSession(); useEffect(() => { const handleSignOut = async () => { try { // Store the user ID before signout clears the session const userId = session?.user?.id; console.log('Starting comprehensive logout process'); // First trigger server-side session cleanup if (userId) { console.log('Triggering server-side session cleanup'); try { const cleanupResponse = await fetch('/api/auth/session-cleanup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId }), credentials: 'include' }); const cleanupResult = await cleanupResponse.json(); console.log('Server cleanup result:', cleanupResult); } catch (cleanupError) { console.error('Error during server-side cleanup:', cleanupError); // Continue with logout even if cleanup fails } } // Then, attempt to sign out from NextAuth explicitly await signOut({ redirect: false }); // Clear Rocket Chat authentication tokens try { console.log('Clearing Rocket Chat tokens'); // Remove cookies document.cookie = `rc_token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname}; SameSite=None; Secure`; document.cookie = `rc_uid=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname}; SameSite=None; Secure`; // Remove localStorage items localStorage.removeItem('Meteor.loginToken'); localStorage.removeItem('Meteor.userId'); // Try to send logout to Rocket Chat server const rocketChatBaseUrl = process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL?.split('/channel')[0]; if (rocketChatBaseUrl) { // This is a best-effort logout - we don't wait for it to complete fetch(`${rocketChatBaseUrl}/api/v1/logout`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }).catch(e => console.error('Failed to notify Rocket Chat server about logout:', e)); } } catch (e) { console.error('Error clearing Rocket Chat tokens:', e); } // Then clear all auth-related cookies to ensure we break any local sessions clearAuthCookies(); // Get Keycloak logout URL if (process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER) { console.log('Preparing complete Keycloak logout'); // Create a proper Keycloak logout URL with all required parameters for front-channel logout const keycloakBaseUrl = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER; const logoutEndpoint = `${keycloakBaseUrl}/protocol/openid-connect/logout`; // Create form for POST logout (more reliable) const form = document.createElement('form'); form.method = 'POST'; form.action = logoutEndpoint; // Add id_token_hint if available if (session?.accessToken) { const tokenInput = document.createElement('input'); tokenInput.type = 'hidden'; tokenInput.name = 'id_token_hint'; tokenInput.value = session.accessToken; form.appendChild(tokenInput); } // Add client_id parameter - CRITICAL for proper logout const clientIdInput = document.createElement('input'); clientIdInput.type = 'hidden'; clientIdInput.name = 'client_id'; clientIdInput.value = process.env.NEXT_PUBLIC_KEYCLOAK_CLIENT_ID || 'lab'; form.appendChild(clientIdInput); // Add post_logout_redirect_uri pointing to our logged out page const redirectInput = document.createElement('input'); redirectInput.type = 'hidden'; redirectInput.name = 'post_logout_redirect_uri'; redirectInput.value = `${window.location.origin}/loggedout`; form.appendChild(redirectInput); // Add logout_hint=server to explicitly request server-side session cleanup const logoutHintInput = document.createElement('input'); logoutHintInput.type = 'hidden'; logoutHintInput.name = 'logout_hint'; logoutHintInput.value = 'server'; form.appendChild(logoutHintInput); // Notify iframe parents before logging out try { // Attempt to notify any iframes that might be using this authentication if (window.parent && window.parent !== window) { window.parent.postMessage({ type: 'LOGOUT_EVENT' }, '*'); } } catch (e) { console.error('Error notifying parent of logout:', e); } // Append to body and submit document.body.appendChild(form); console.log('Submitting Keycloak logout form with server-side logout'); form.submit(); } else { console.log('No Keycloak configuration found, performing simple redirect'); window.location.href = '/loggedout'; } } catch (error) { console.error('Error during logout:', error); window.location.href = '/loggedout'; } }; // Add a slight delay to ensure useSession has loaded const timer = setTimeout(() => { handleSignOut(); }, 100); return () => clearTimeout(timer); }, [session]); return (

Logging out...

Please wait while we sign you out completely.

); }