auth flow
This commit is contained in:
parent
3be309c0fe
commit
d488979109
@ -83,16 +83,27 @@ export const authOptions: NextAuthOptions = {
|
|||||||
callbacks: {
|
callbacks: {
|
||||||
async jwt({ token, account, profile }: any) {
|
async jwt({ token, account, profile }: any) {
|
||||||
if (account && profile) {
|
if (account && profile) {
|
||||||
// Just store access token and critical fields
|
// Store access token
|
||||||
token.accessToken = account.access_token;
|
token.accessToken = account.access_token;
|
||||||
// Make sure roles are available
|
token.refreshToken = account.refresh_token;
|
||||||
if (profile.role) {
|
|
||||||
|
// Extract roles correctly from the raw Keycloak profile
|
||||||
|
if (profile.realm_access && profile.realm_access.roles) {
|
||||||
|
// Directly extract roles from the Keycloak profile structure
|
||||||
|
token.role = profile.realm_access.roles.map(
|
||||||
|
(role: string) => role.replace(/^ROLE_/, '').toLowerCase()
|
||||||
|
);
|
||||||
|
} else if (profile.role) {
|
||||||
|
// Fallback to using the role property if already processed
|
||||||
token.role = profile.role;
|
token.role = profile.role;
|
||||||
token.username = profile.username || '';
|
|
||||||
token.first_name = profile.first_name || '';
|
|
||||||
token.last_name = profile.last_name || '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store user information
|
||||||
|
token.username = profile.preferred_username || profile.username || '';
|
||||||
|
token.first_name = profile.given_name || profile.first_name || '';
|
||||||
|
token.last_name = profile.family_name || profile.last_name || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return token;
|
return token;
|
||||||
},
|
},
|
||||||
async session({ session, token }: any) {
|
async session({ session, token }: any) {
|
||||||
@ -102,7 +113,7 @@ export const authOptions: NextAuthOptions = {
|
|||||||
session.user.id = token.sub || "";
|
session.user.id = token.sub || "";
|
||||||
|
|
||||||
// Ensure roles are passed to the session
|
// Ensure roles are passed to the session
|
||||||
if (token.role) {
|
if (token.role && Array.isArray(token.role)) {
|
||||||
session.user.role = token.role;
|
session.user.role = token.role;
|
||||||
session.user.username = token.username || '';
|
session.user.username = token.username || '';
|
||||||
session.user.first_name = token.first_name || '';
|
session.user.first_name = token.first_name || '';
|
||||||
@ -114,6 +125,9 @@ export const authOptions: NextAuthOptions = {
|
|||||||
session.user.first_name = '';
|
session.user.first_name = '';
|
||||||
session.user.last_name = '';
|
session.user.last_name = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add debug log to see what roles are being passed
|
||||||
|
console.log('Session user roles:', session.user.role);
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@ -133,7 +147,7 @@ export const authOptions: NextAuthOptions = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
debug: false,
|
debug: true, // Enable debug logs temporarily to see role information
|
||||||
};
|
};
|
||||||
|
|
||||||
const handler = NextAuth(authOptions);
|
const handler = NextAuth(authOptions);
|
||||||
|
|||||||
@ -11,12 +11,13 @@ export default function SignIn() {
|
|||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Clear cookies on errors or manual signout
|
// Always clear cookies on signin page load to ensure fresh authentication
|
||||||
|
clearAuthCookies();
|
||||||
|
|
||||||
|
// Set error message if present
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log("Clearing auth cookies due to error:", error);
|
console.log("Clearing auth cookies due to error:", error);
|
||||||
clearAuthCookies();
|
|
||||||
|
|
||||||
// Set error message
|
|
||||||
if (error === "RefreshTokenError" || error === "invalid_grant") {
|
if (error === "RefreshTokenError" || error === "invalid_grant") {
|
||||||
setMessage("Your session has expired. Please sign in again.");
|
setMessage("Your session has expired. Please sign in again.");
|
||||||
} else {
|
} else {
|
||||||
@ -25,9 +26,24 @@ export default function SignIn() {
|
|||||||
}
|
}
|
||||||
}, [error]);
|
}, [error]);
|
||||||
|
|
||||||
// Simple login function
|
// Login function with callbackUrl to maintain original destination
|
||||||
const handleSignIn = () => {
|
const handleSignIn = () => {
|
||||||
signIn("keycloak", { callbackUrl: "/" });
|
// Get the callback URL from the query parameters or use the home page
|
||||||
|
const callbackUrl = searchParams.get("callbackUrl") || "/";
|
||||||
|
|
||||||
|
// Add a timestamp parameter to avoid caching issues
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
const authParams = {
|
||||||
|
callbackUrl,
|
||||||
|
redirect: true,
|
||||||
|
// Adding a timestamp to force Keycloak to skip any cached session
|
||||||
|
authParams: {
|
||||||
|
prompt: "login",
|
||||||
|
t: timestamp.toString()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
signIn("keycloak", authParams);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -114,17 +114,87 @@ export function clearAuthCookies() {
|
|||||||
// Get all cookies to check for chunked auth cookies
|
// Get all cookies to check for chunked auth cookies
|
||||||
const cookies = document.cookie.split(';');
|
const cookies = document.cookie.split(';');
|
||||||
|
|
||||||
// Clear main auth cookies
|
// Try multiple path and domain combinations for thorough cleanup
|
||||||
|
const paths = ['/', '/auth', '/realms', '/admin'];
|
||||||
|
const domain = window.location.hostname;
|
||||||
|
const domains = [
|
||||||
|
domain,
|
||||||
|
`.${domain}`,
|
||||||
|
domain.split('.').slice(-2).join('.'),
|
||||||
|
`.${domain.split('.').slice(-2).join('.')}`
|
||||||
|
];
|
||||||
|
|
||||||
|
// Clear main auth cookies with all path/domain combinations
|
||||||
authCookies.forEach(cookieName => {
|
authCookies.forEach(cookieName => {
|
||||||
|
// Basic deletion
|
||||||
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=None; Secure`;
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=None; Secure`;
|
||||||
|
|
||||||
|
// Try more aggressive deletion with different paths and domains
|
||||||
|
paths.forEach(path => {
|
||||||
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; SameSite=None; Secure`;
|
||||||
|
|
||||||
|
domains.forEach(domainValue => {
|
||||||
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domainValue}; SameSite=None; Secure`;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for and clear any chunked cookies
|
// Check for and clear any chunked cookies and cookies with dynamic names
|
||||||
cookies.forEach(cookie => {
|
cookies.forEach(cookie => {
|
||||||
const cookieName = cookie.split('=')[0].trim();
|
const cookieName = cookie.split('=')[0].trim();
|
||||||
// Check for chunked cookies (they end with a number)
|
|
||||||
if (cookieName.startsWith('next-auth.') && /\.\d+$/.test(cookieName)) {
|
// Clear chunked cookies (end with a number) and any auth-related cookies
|
||||||
|
if (cookieName.startsWith('next-auth.') ||
|
||||||
|
cookieName.includes('keycloak') ||
|
||||||
|
cookieName.includes('auth') ||
|
||||||
|
cookieName.includes('session') ||
|
||||||
|
/\.\d+$/.test(cookieName)) {
|
||||||
|
|
||||||
|
// Basic deletion
|
||||||
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=None; Secure`;
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=None; Secure`;
|
||||||
|
|
||||||
|
// Try more aggressive deletion with different paths and domains
|
||||||
|
paths.forEach(path => {
|
||||||
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; SameSite=None; Secure`;
|
||||||
|
|
||||||
|
domains.forEach(domainValue => {
|
||||||
|
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domainValue}; SameSite=None; Secure`;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Clear localStorage items related to authentication
|
||||||
|
try {
|
||||||
|
const authItems = [
|
||||||
|
'Meteor.loginToken',
|
||||||
|
'Meteor.userId',
|
||||||
|
'token',
|
||||||
|
'refreshToken',
|
||||||
|
'userId',
|
||||||
|
'userName',
|
||||||
|
'userEmail'
|
||||||
|
];
|
||||||
|
|
||||||
|
authItems.forEach(item => {
|
||||||
|
localStorage.removeItem(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Also look for any items with auth-related names
|
||||||
|
for (let i = 0; i < localStorage.length; i++) {
|
||||||
|
const key = localStorage.key(i);
|
||||||
|
if (key && (key.includes('token') || key.includes('auth') || key.includes('session'))) {
|
||||||
|
localStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to clear localStorage:', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all sessionStorage
|
||||||
|
try {
|
||||||
|
sessionStorage.clear();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to clear sessionStorage:', e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user