209 lines
7.3 KiB
TypeScript
209 lines
7.3 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import { clearAuthCookies } from "@/lib/session";
|
|
import Link from "next/link";
|
|
|
|
export default function LoggedOut() {
|
|
const [sessionStatus, setSessionStatus] = useState<'checking' | 'cleared' | 'error'>('checking');
|
|
|
|
// Listen for any messages from iframes
|
|
useEffect(() => {
|
|
const messageHandler = (event: MessageEvent) => {
|
|
// Handle any auth-related messages from iframes
|
|
if (event.data && event.data.type === 'AUTH_ERROR') {
|
|
console.log('Received auth error from iframe:', event.data);
|
|
}
|
|
};
|
|
|
|
window.addEventListener('message', messageHandler);
|
|
return () => window.removeEventListener('message', messageHandler);
|
|
}, []);
|
|
|
|
// Clear auth cookies again on this page as an extra precaution
|
|
useEffect(() => {
|
|
const checkAndClearSessions = async () => {
|
|
try {
|
|
// Additional browser storage clearing
|
|
console.log('Performing complete browser storage cleanup');
|
|
|
|
// Try to get any user ID from localStorage or sessionStorage for server-side cleanup
|
|
let userId = '';
|
|
try {
|
|
// Check standard localStorage locations for userId
|
|
const possibleUserIdKeys = [
|
|
'userId',
|
|
'user_id',
|
|
'currentUser',
|
|
'user',
|
|
'keycloak.userId',
|
|
'auth.userId'
|
|
];
|
|
|
|
for (const key of possibleUserIdKeys) {
|
|
const value = localStorage.getItem(key) || sessionStorage.getItem(key);
|
|
if (value) {
|
|
try {
|
|
// It might be a JSON object
|
|
const parsed = JSON.parse(value);
|
|
userId = parsed.id || parsed.userId || parsed.user_id || parsed.sub || '';
|
|
if (userId) break;
|
|
} catch {
|
|
// Or it might be a plain string
|
|
userId = value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('Found user ID for server cleanup:', userId || 'None found');
|
|
} catch (e) {
|
|
console.error('Error getting user ID from storage:', e);
|
|
}
|
|
|
|
// Call the server-side cleanup if we have a user ID
|
|
if (userId) {
|
|
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-side cleanup result:', cleanupResult);
|
|
} catch (e) {
|
|
console.error('Error calling server-side cleanup:', e);
|
|
}
|
|
}
|
|
|
|
// Clear cookies
|
|
clearAuthCookies();
|
|
|
|
// Clear session storage
|
|
try {
|
|
sessionStorage.clear();
|
|
console.log('Session storage cleared');
|
|
} catch (e) {
|
|
console.error('Error clearing session storage:', e);
|
|
}
|
|
|
|
// Clear local storage items related to auth
|
|
try {
|
|
const authLocalStoragePrefixes = ['token', 'auth', 'session', 'keycloak', 'kc', 'oidc', 'user', 'meteor'];
|
|
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
const key = localStorage.key(i);
|
|
if (key) {
|
|
const keyLower = key.toLowerCase();
|
|
if (authLocalStoragePrefixes.some(prefix => keyLower.includes(prefix))) {
|
|
console.log(`Clearing localStorage: ${key}`);
|
|
localStorage.removeItem(key);
|
|
}
|
|
}
|
|
}
|
|
console.log('Local storage auth items cleared');
|
|
} catch (e) {
|
|
console.error('Error clearing localStorage:', e);
|
|
}
|
|
|
|
// Double check for Keycloak specific cookies and chunked cookies
|
|
const cookies = document.cookie.split(';');
|
|
const cookieNames = cookies.map(cookie => cookie.split('=')[0].trim());
|
|
|
|
// Look for chunked cookies
|
|
const chunkedCookies = cookieNames.filter(name => /\.\d+$/.test(name));
|
|
|
|
const keycloakCookies = [
|
|
'KEYCLOAK_SESSION',
|
|
'KEYCLOAK_IDENTITY',
|
|
'KC_RESTART',
|
|
'rc_token',
|
|
'rc_uid',
|
|
'Meteor.loginToken',
|
|
...chunkedCookies
|
|
];
|
|
|
|
for (const cookieName of keycloakCookies) {
|
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname}; SameSite=None; Secure;`;
|
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
|
|
|
// Also try with root domain
|
|
const rootDomain = window.location.hostname.split('.').slice(-2).join('.');
|
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=.${rootDomain}; SameSite=None; Secure;`;
|
|
}
|
|
|
|
// Notify any parent windows/iframes
|
|
try {
|
|
if (window.parent && window.parent !== window) {
|
|
window.parent.postMessage({ type: 'SESSION_CLEARED' }, '*');
|
|
}
|
|
} catch (e) {
|
|
console.error('Error notifying parent window:', e);
|
|
}
|
|
|
|
setSessionStatus('cleared');
|
|
} catch (error) {
|
|
console.error('Error during session cleanup:', error);
|
|
setSessionStatus('error');
|
|
}
|
|
};
|
|
|
|
checkAndClearSessions();
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
className="min-h-screen flex items-center justify-center"
|
|
style={{
|
|
backgroundImage: "url('/signin.jpg')",
|
|
backgroundSize: 'cover',
|
|
backgroundPosition: 'center',
|
|
backgroundRepeat: 'no-repeat'
|
|
}}
|
|
>
|
|
<div className="w-full max-w-md p-8 bg-black/60 backdrop-blur-sm rounded-lg shadow-xl">
|
|
<div className="text-center">
|
|
<h2 className="text-3xl font-bold text-white mb-4">
|
|
You have been logged out
|
|
</h2>
|
|
|
|
{sessionStatus === 'checking' && (
|
|
<p className="text-white/80 mb-4">
|
|
Verifying all sessions are terminated...
|
|
</p>
|
|
)}
|
|
|
|
{sessionStatus === 'cleared' && (
|
|
<p className="text-white/80 mb-4">
|
|
Your session has been completely terminated and all authentication data has been cleared.
|
|
</p>
|
|
)}
|
|
|
|
{sessionStatus === 'error' && (
|
|
<p className="text-white/80 mb-4">
|
|
Your session has been terminated, but there might be some residual session data.
|
|
For complete security, please close your browser.
|
|
</p>
|
|
)}
|
|
|
|
<div className="mt-6">
|
|
<Link
|
|
href="/signin?signedOut=true"
|
|
className="inline-block px-8 py-3 bg-white text-gray-800 rounded hover:bg-gray-100 transition-colors mb-4"
|
|
>
|
|
Sign In Again
|
|
</Link>
|
|
|
|
<p className="text-white/60 text-sm mt-4">
|
|
Note: If you're automatically signed in again, try clearing your browser cookies or restarting your browser.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|