keycloak improve with build 3

This commit is contained in:
alma 2026-01-02 15:30:18 +01:00
parent 7a8b736241
commit ff7e022ee7
5 changed files with 73 additions and 17 deletions

View File

@ -8,6 +8,19 @@ import { authOptions } from '../options';
*/
export async function GET(request: NextRequest) {
try {
// Check if user just logged out (prevent refresh after logout)
const logoutCookie = request.cookies.get('logout_in_progress');
if (logoutCookie?.value === 'true') {
console.log('Logout in progress, refusing to refresh session');
return NextResponse.json(
{
error: 'SessionInvalidated',
message: 'User is logging out. Please sign in again.'
},
{ status: 401 }
);
}
const session = await getServerSession(authOptions);
if (!session?.accessToken || !session?.refreshToken) {

View File

@ -24,6 +24,16 @@ export function ResponsiveIframe({ src, className = '', allow, style }: Responsi
return;
}
// Check if user just logged out - prevent refresh if logout is in progress
const justLoggedOut = sessionStorage.getItem('just_logged_out') === 'true';
const logoutCookie = document.cookie.split(';').some(c => c.trim().startsWith('logout_in_progress=true'));
if (justLoggedOut || logoutCookie) {
console.warn('Logout in progress, redirecting to sign-in instead of refreshing session');
window.location.href = '/signin';
return;
}
// If no session yet, wait for it (don't set src yet)
if (!session) {
return;
@ -52,6 +62,14 @@ export function ResponsiveIframe({ src, className = '', allow, style }: Responsi
// Wait a bit to ensure NextAuth session is fully established
await new Promise(resolve => setTimeout(resolve, 100));
// Double-check logout flag before making the request
const stillLoggedOut = sessionStorage.getItem('just_logged_out') === 'true';
if (stillLoggedOut) {
console.warn('Logout detected during refresh, aborting');
window.location.href = '/signin';
return;
}
// Call our API to refresh the Keycloak session
// This ensures tokens are fresh and may help refresh Keycloak session cookies
const response = await fetch('/api/auth/refresh-keycloak-session', {

View File

@ -14,12 +14,28 @@ export default function Home() {
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
// Check if logout is in progress - if so, redirect immediately
const justLoggedOut = sessionStorage.getItem('just_logged_out') === 'true';
const logoutCookie = document.cookie.split(';').some(c => c.trim().startsWith('logout_in_progress=true'));
if (justLoggedOut || logoutCookie) {
// Clear the flags and redirect
sessionStorage.removeItem('just_logged_out');
document.cookie = 'logout_in_progress=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC';
window.location.href = '/signin?logout=true';
return;
}
if (status !== "loading") {
setIsLoading(false);
}
}, [status]);
if (isLoading) {
// Don't render widgets if logout is in progress
const justLoggedOut = sessionStorage.getItem('just_logged_out') === 'true';
const logoutCookie = document.cookie.split(';').some(c => c.trim().startsWith('logout_in_progress=true'));
if (isLoading || justLoggedOut || logoutCookie) {
return (
<main className="h-screen flex items-center justify-center">
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-900"></div>

View File

@ -10,22 +10,24 @@ export function SignOutHandler() {
useEffect(() => {
const handleSignOut = async () => {
try {
// Mark that we're logging out to prevent auto-login
// 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;
// First, sign out from NextAuth (clears NextAuth cookies)
// Clear NextAuth cookies immediately before signOut
clearAuthCookies();
// Sign out from NextAuth (clears NextAuth session)
await signOut({
callbackUrl: "/signin?logout=true",
redirect: false
});
// Clear NextAuth cookies client-side
clearAuthCookies();
// If we have Keycloak ID token and issuer, call Keycloak logout
if (keycloakIssuer && idToken) {
const keycloakLogoutUrl = new URL(
@ -42,16 +44,16 @@ export function SignOutHandler() {
idToken
);
// Redirect to Keycloak logout (this will clear Keycloak cookies)
window.location.href = keycloakLogoutUrl.toString();
// 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.href = '/signin?logout=true';
window.location.replace('/signin?logout=true');
}
} catch (error) {
console.error('Error during sign out:', error);
// Fallback: redirect to signin on error
window.location.href = '/signin?logout=true';
window.location.replace('/signin?logout=true');
}
};

View File

@ -28,6 +28,7 @@ import Image from "next/image";
import Link from "next/link";
import { Sidebar } from "./sidebar";
import { useSession, signIn, signOut } from "next-auth/react";
import { clearAuthCookies } from "@/lib/session";
import {
DropdownMenu,
DropdownMenuContent,
@ -362,19 +363,25 @@ export function MainNav() {
className="text-white/80 hover:text-white hover:bg-black/50 cursor-pointer"
onClick={async () => {
try {
// Mark that we're logging out to prevent auto-login
// 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
const keycloakIssuer = process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER;
const idToken = session?.idToken;
// First sign out from NextAuth (clears NextAuth cookies)
// Clear NextAuth cookies immediately before signOut
clearAuthCookies();
// 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
// Force immediate redirect to prevent widgets from rendering
// This ensures session state is cleared before any components re-render
if (keycloakIssuer && idToken) {
const keycloakLogoutUrl = new URL(
`${keycloakIssuer}/protocol/openid-connect/logout`
@ -390,16 +397,16 @@ export function MainNav() {
idToken
);
// Redirect to Keycloak logout (this will clear Keycloak cookies)
window.location.href = keycloakLogoutUrl.toString();
// 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.href = '/signin?logout=true';
window.location.replace('/signin?logout=true');
}
} catch (error) {
console.error('Error during logout:', error);
// Fallback to simple redirect if something goes wrong
window.location.href = '/signin?logout=true';
window.location.replace('/signin?logout=true');
}
}}
>