auth flow
This commit is contained in:
parent
a171e4a713
commit
ecd587fd8c
7
app/loggedout/layout.tsx
Normal file
7
app/loggedout/layout.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
export default function LoggedOutLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return children;
|
||||
}
|
||||
49
app/loggedout/page.tsx
Normal file
49
app/loggedout/page.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { clearAuthCookies } from "@/lib/session";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function LoggedOut() {
|
||||
// Clear auth cookies again on this page as an extra precaution
|
||||
useEffect(() => {
|
||||
// Run an additional cookie cleanup on this page
|
||||
clearAuthCookies();
|
||||
|
||||
// Also clear session storage
|
||||
try {
|
||||
sessionStorage.clear();
|
||||
} catch (e) {
|
||||
console.error('Error clearing session storage:', e);
|
||||
}
|
||||
}, []);
|
||||
|
||||
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>
|
||||
<p className="text-white/80 mb-8">
|
||||
Your session has been successfully terminated and all authentication data has been cleared.
|
||||
</p>
|
||||
<Link
|
||||
href="/signin"
|
||||
className="inline-block px-8 py-3 bg-white text-gray-800 rounded hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
Sign In Again
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -9,15 +9,34 @@ export default function SignIn() {
|
||||
const searchParams = useSearchParams();
|
||||
const signedOut = searchParams.get('signedOut') === 'true';
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
const [isFromLogout, setIsFromLogout] = useState(false);
|
||||
|
||||
// Check if we came from the loggedout page
|
||||
useEffect(() => {
|
||||
const referrer = document.referrer;
|
||||
const isFromLoggedOutPage = referrer &&
|
||||
(referrer.includes('/loggedout') || referrer.includes('/signout'));
|
||||
|
||||
if (isFromLoggedOutPage) {
|
||||
console.log('Detected navigation from logout page, preventing auto-login');
|
||||
setIsFromLogout(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Only automatically sign in if not explicitly signed out
|
||||
if (!signedOut && !isRedirecting) {
|
||||
// Only automatically sign in if not explicitly signed out and not coming from logout
|
||||
if (!signedOut && !isFromLogout && !isRedirecting && !session) {
|
||||
setIsRedirecting(true);
|
||||
// Trigger Keycloak sign-in
|
||||
signIn("keycloak", { callbackUrl: "/" });
|
||||
console.log('Triggering automatic sign-in');
|
||||
// Add a small delay to avoid immediate redirect which can cause loops
|
||||
const timer = setTimeout(() => {
|
||||
// Trigger Keycloak sign-in
|
||||
signIn("keycloak", { callbackUrl: "/" });
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [signedOut, isRedirecting]);
|
||||
}, [signedOut, isRedirecting, isFromLogout, session]);
|
||||
|
||||
useEffect(() => {
|
||||
if (session?.user && !session.user.nextcloudInitialized) {
|
||||
@ -34,6 +53,8 @@ export default function SignIn() {
|
||||
}
|
||||
}, [session]);
|
||||
|
||||
const showManualLoginButton = signedOut || isFromLogout || isRedirecting;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="min-h-screen flex items-center justify-center"
|
||||
@ -46,17 +67,20 @@ export default function SignIn() {
|
||||
>
|
||||
<div className="w-full max-w-md space-y-8">
|
||||
<div>
|
||||
{signedOut ? (
|
||||
{showManualLoginButton ? (
|
||||
<>
|
||||
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-white">
|
||||
You have been signed out
|
||||
{signedOut || isFromLogout ? 'You have been signed out' : 'Welcome Back'}
|
||||
</h2>
|
||||
<p className="mt-2 text-center text-lg text-white/80">
|
||||
Click below to sign in again
|
||||
Click below to sign in
|
||||
</p>
|
||||
<div className="mt-6 flex justify-center">
|
||||
<button
|
||||
onClick={() => signIn("keycloak", { callbackUrl: "/" })}
|
||||
onClick={() => {
|
||||
setIsRedirecting(true);
|
||||
signIn("keycloak", { callbackUrl: "/" });
|
||||
}}
|
||||
className="px-8 py-3 bg-white text-gray-800 rounded hover:bg-gray-100 transition-colors"
|
||||
>
|
||||
Sign In
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { signOut, useSession } from "next-auth/react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { clearAuthCookies } from "@/lib/session";
|
||||
|
||||
export function SignOutHandler() {
|
||||
@ -10,49 +10,63 @@ export function SignOutHandler() {
|
||||
useEffect(() => {
|
||||
const handleSignOut = async () => {
|
||||
try {
|
||||
// Clear all auth-related cookies
|
||||
// First, clear all auth-related cookies to ensure we break any local sessions
|
||||
clearAuthCookies();
|
||||
|
||||
// First sign out from NextAuth with redirect false
|
||||
await signOut({
|
||||
redirect: false
|
||||
});
|
||||
|
||||
// Then redirect to Keycloak logout with proper parameters
|
||||
if (process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER) {
|
||||
const keycloakLogoutUrl = new URL(
|
||||
`${process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER}/protocol/openid-connect/logout`
|
||||
);
|
||||
// Create a temporary HTML form for direct POST logout (more reliable than redirect)
|
||||
if (process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER && session?.accessToken) {
|
||||
console.log('Directly calling Keycloak logout endpoint');
|
||||
|
||||
// Add required parameters
|
||||
keycloakLogoutUrl.searchParams.append(
|
||||
'post_logout_redirect_uri',
|
||||
`${window.location.origin}/signin?signedOut=true`
|
||||
);
|
||||
// Create a hidden form for POST logout
|
||||
const form = document.createElement('form');
|
||||
form.method = 'POST';
|
||||
form.action = `${process.env.NEXT_PUBLIC_KEYCLOAK_ISSUER}/protocol/openid-connect/logout`;
|
||||
|
||||
// Add id_token_hint if available
|
||||
if (session?.accessToken) {
|
||||
keycloakLogoutUrl.searchParams.append(
|
||||
'id_token_hint',
|
||||
session.accessToken
|
||||
);
|
||||
// Add the id_token_hint
|
||||
if (session.accessToken) {
|
||||
const tokenInput = document.createElement('input');
|
||||
tokenInput.type = 'hidden';
|
||||
tokenInput.name = 'id_token_hint';
|
||||
tokenInput.value = session.accessToken;
|
||||
form.appendChild(tokenInput);
|
||||
}
|
||||
|
||||
// Redirect to Keycloak logout
|
||||
window.location.href = keycloakLogoutUrl.toString();
|
||||
// Add post_logout_redirect_uri pointing to a special loggedout page
|
||||
const redirectInput = document.createElement('input');
|
||||
redirectInput.type = 'hidden';
|
||||
redirectInput.name = 'post_logout_redirect_uri';
|
||||
redirectInput.value = `${window.location.origin}/loggedout`;
|
||||
form.appendChild(redirectInput);
|
||||
|
||||
// Append to body and submit
|
||||
document.body.appendChild(form);
|
||||
form.submit();
|
||||
} else {
|
||||
// Fallback if no Keycloak issuer is configured
|
||||
window.location.href = '/signin?signedOut=true';
|
||||
console.log('No Keycloak configuration found, performing simple redirect');
|
||||
// Fallback if no Keycloak config or session
|
||||
window.location.href = '/loggedout';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error during logout:', error);
|
||||
// Fallback if something goes wrong
|
||||
window.location.href = '/signin?signedOut=true';
|
||||
window.location.href = '/loggedout';
|
||||
}
|
||||
};
|
||||
|
||||
handleSignOut();
|
||||
// Add a slight delay to ensure useSession has loaded
|
||||
const timer = setTimeout(() => {
|
||||
handleSignOut();
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [session]);
|
||||
|
||||
return null;
|
||||
return (
|
||||
<div className="w-full h-full flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-bold">Logging out...</h2>
|
||||
<p className="text-gray-500 mt-2">Please wait while we sign you out.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user