auth flow
This commit is contained in:
parent
97479aaa35
commit
a171e4a713
@ -1,15 +1,23 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { signIn, useSession } from "next-auth/react";
|
import { signIn, useSession } from "next-auth/react";
|
||||||
import { useEffect } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { useSearchParams } from "next/navigation";
|
||||||
|
|
||||||
export default function SignIn() {
|
export default function SignIn() {
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
|
const searchParams = useSearchParams();
|
||||||
|
const signedOut = searchParams.get('signedOut') === 'true';
|
||||||
|
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Trigger Keycloak sign-in
|
// Only automatically sign in if not explicitly signed out
|
||||||
signIn("keycloak", { callbackUrl: "/" });
|
if (!signedOut && !isRedirecting) {
|
||||||
}, []);
|
setIsRedirecting(true);
|
||||||
|
// Trigger Keycloak sign-in
|
||||||
|
signIn("keycloak", { callbackUrl: "/" });
|
||||||
|
}
|
||||||
|
}, [signedOut, isRedirecting]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session?.user && !session.user.nextcloudInitialized) {
|
if (session?.user && !session.user.nextcloudInitialized) {
|
||||||
@ -38,9 +46,28 @@ export default function SignIn() {
|
|||||||
>
|
>
|
||||||
<div className="w-full max-w-md space-y-8">
|
<div className="w-full max-w-md space-y-8">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-white">
|
{signedOut ? (
|
||||||
Redirecting to login...
|
<>
|
||||||
</h2>
|
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-white">
|
||||||
|
You have been signed out
|
||||||
|
</h2>
|
||||||
|
<p className="mt-2 text-center text-lg text-white/80">
|
||||||
|
Click below to sign in again
|
||||||
|
</p>
|
||||||
|
<div className="mt-6 flex justify-center">
|
||||||
|
<button
|
||||||
|
onClick={() => signIn("keycloak", { callbackUrl: "/" })}
|
||||||
|
className="px-8 py-3 bg-white text-gray-800 rounded hover:bg-gray-100 transition-colors"
|
||||||
|
>
|
||||||
|
Sign In
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-white">
|
||||||
|
Redirecting to login...
|
||||||
|
</h2>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,24 +1,58 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { signOut } from "next-auth/react";
|
import { signOut, useSession } from "next-auth/react";
|
||||||
import { clearAuthCookies } from "@/lib/session";
|
import { clearAuthCookies } from "@/lib/session";
|
||||||
|
|
||||||
export function SignOutHandler() {
|
export function SignOutHandler() {
|
||||||
|
const { data: session } = useSession();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleSignOut = async () => {
|
const handleSignOut = async () => {
|
||||||
// Clear only auth-related cookies
|
try {
|
||||||
clearAuthCookies();
|
// Clear all auth-related cookies
|
||||||
|
clearAuthCookies();
|
||||||
// Then sign out from NextAuth
|
|
||||||
await signOut({
|
// First sign out from NextAuth with redirect false
|
||||||
callbackUrl: "/signin",
|
await signOut({
|
||||||
redirect: true
|
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`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add required parameters
|
||||||
|
keycloakLogoutUrl.searchParams.append(
|
||||||
|
'post_logout_redirect_uri',
|
||||||
|
`${window.location.origin}/signin?signedOut=true`
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add id_token_hint if available
|
||||||
|
if (session?.accessToken) {
|
||||||
|
keycloakLogoutUrl.searchParams.append(
|
||||||
|
'id_token_hint',
|
||||||
|
session.accessToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect to Keycloak logout
|
||||||
|
window.location.href = keycloakLogoutUrl.toString();
|
||||||
|
} else {
|
||||||
|
// Fallback if no Keycloak issuer is configured
|
||||||
|
window.location.href = '/signin?signedOut=true';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error during logout:', error);
|
||||||
|
// Fallback if something goes wrong
|
||||||
|
window.location.href = '/signin?signedOut=true';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleSignOut();
|
handleSignOut();
|
||||||
}, []);
|
}, [session]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -92,11 +92,68 @@ export async function invalidateServiceTokens(session: ExtendedSession) {
|
|||||||
|
|
||||||
export function clearAuthCookies() {
|
export function clearAuthCookies() {
|
||||||
const cookies = document.cookie.split(';');
|
const cookies = document.cookie.split(';');
|
||||||
|
console.log('Clearing all auth cookies');
|
||||||
|
|
||||||
|
// List of known auth-related cookie prefixes
|
||||||
|
const authCookiePrefixes = [
|
||||||
|
'next-auth.',
|
||||||
|
'__Secure-next-auth.',
|
||||||
|
'__Host-next-auth.',
|
||||||
|
'KEYCLOAK_',
|
||||||
|
'KC_',
|
||||||
|
'JSESSIONID',
|
||||||
|
'OAuth_Token_Request_State',
|
||||||
|
'OAUTH2_CLIENT_ID',
|
||||||
|
'OAUTH2_STATE',
|
||||||
|
'XSRF-TOKEN'
|
||||||
|
];
|
||||||
|
|
||||||
for (const cookie of cookies) {
|
for (const cookie of cookies) {
|
||||||
const [name] = cookie.split('=');
|
const [name] = cookie.split('=');
|
||||||
// Only clear auth-related cookies
|
const trimmedName = name.trim();
|
||||||
if (name.trim().startsWith('next-auth.') || name.trim().startsWith('__Secure-next-auth.') || name.trim().startsWith('__Host-next-auth.')) {
|
|
||||||
document.cookie = `${name.trim()}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
// Check if this is an auth-related cookie
|
||||||
|
const isAuthCookie = authCookiePrefixes.some(prefix =>
|
||||||
|
trimmedName.startsWith(prefix)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Also clear cookies with auth-related terms
|
||||||
|
const containsAuthTerm =
|
||||||
|
trimmedName.toLowerCase().includes('auth') ||
|
||||||
|
trimmedName.toLowerCase().includes('token') ||
|
||||||
|
trimmedName.toLowerCase().includes('session');
|
||||||
|
|
||||||
|
if (isAuthCookie || containsAuthTerm) {
|
||||||
|
console.log(`Clearing cookie: ${trimmedName}`);
|
||||||
|
|
||||||
|
// Clear the cookie with various domain/path combinations
|
||||||
|
// Standard path
|
||||||
|
document.cookie = `${trimmedName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||||||
|
|
||||||
|
// Root domain
|
||||||
|
const domain = window.location.hostname.split('.').slice(-2).join('.');
|
||||||
|
document.cookie = `${trimmedName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain};`;
|
||||||
|
|
||||||
|
// Full domain
|
||||||
|
document.cookie = `${trimmedName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname};`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear localStorage items that might be related to authentication
|
||||||
|
try {
|
||||||
|
const authLocalStoragePrefixes = ['token', 'auth', 'session', 'keycloak', 'kc', 'user'];
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error clearing localStorage:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user