auth flow
This commit is contained in:
parent
e76e92b695
commit
a5f672726a
@ -60,61 +60,18 @@ export const authOptions: NextAuthOptions = {
|
||||
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
|
||||
issuer: process.env.KEYCLOAK_ISSUER || "",
|
||||
profile(profile: any) {
|
||||
// Debug the raw profile from Keycloak to understand its structure
|
||||
console.log('Raw Keycloak profile:', JSON.stringify(profile, null, 2));
|
||||
|
||||
// Extract roles from realm_access.roles and resource_access
|
||||
let roles: string[] = [];
|
||||
|
||||
// Get roles from realm_access
|
||||
if (profile.realm_access && Array.isArray(profile.realm_access.roles)) {
|
||||
roles = roles.concat(profile.realm_access.roles);
|
||||
}
|
||||
|
||||
// Get roles from resource_access for the client
|
||||
if (profile.resource_access) {
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
if (clientId && profile.resource_access[clientId] && Array.isArray(profile.resource_access[clientId].roles)) {
|
||||
roles = roles.concat(profile.resource_access[clientId].roles);
|
||||
}
|
||||
|
||||
// Also check resource_access roles under 'account'
|
||||
if (profile.resource_access.account && Array.isArray(profile.resource_access.account.roles)) {
|
||||
roles = roles.concat(profile.resource_access.account.roles);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract groups if available
|
||||
if (profile.groups && Array.isArray(profile.groups)) {
|
||||
// Remove any path prefixes (like "/") and add as roles
|
||||
const groupRoles = profile.groups.map((group: string) =>
|
||||
group.replace(/^\//, '').toLowerCase()
|
||||
);
|
||||
roles = roles.concat(groupRoles);
|
||||
}
|
||||
|
||||
// Clean up roles and convert to lowercase
|
||||
const cleanedRoles = roles
|
||||
.filter(Boolean) // Remove empty roles
|
||||
.map((role: string) =>
|
||||
role.replace(/^ROLE_/, '').toLowerCase()
|
||||
);
|
||||
|
||||
// Add some common application-specific role mappings
|
||||
const applicationRoles = mapToApplicationRoles(cleanedRoles);
|
||||
const allRoles = [...new Set([...cleanedRoles, ...applicationRoles, 'user'])];
|
||||
|
||||
console.log('Extracted roles:', allRoles);
|
||||
|
||||
// Just return a simple profile with required fields
|
||||
return {
|
||||
id: profile.sub,
|
||||
name: profile.name || profile.preferred_username,
|
||||
email: profile.email,
|
||||
image: null,
|
||||
role: allRoles,
|
||||
username: profile.preferred_username || profile.email?.split('@')[0] || '',
|
||||
first_name: profile.given_name || '',
|
||||
last_name: profile.family_name || '',
|
||||
username: profile.preferred_username || profile.email?.split('@')[0] || '',
|
||||
role: ['user'],
|
||||
// Store raw profile data for later processing
|
||||
raw_profile: profile
|
||||
};
|
||||
}
|
||||
}),
|
||||
@ -124,33 +81,108 @@ export const authOptions: NextAuthOptions = {
|
||||
maxAge: 8 * 60 * 60, // 8 hours
|
||||
},
|
||||
callbacks: {
|
||||
async jwt({ token, account, profile }: any) {
|
||||
if (account && profile) {
|
||||
// Store access token
|
||||
async jwt({ token, account, profile, user }: any) {
|
||||
// Debug input parameters to understand what's available
|
||||
console.log('JWT callback - input parameters:', {
|
||||
hasAccount: !!account,
|
||||
hasProfile: !!profile,
|
||||
hasUser: !!user,
|
||||
hasToken: !!token,
|
||||
tokenSub: token?.sub,
|
||||
tokenAccessToken: token?.accessToken ? '[exists]' : undefined
|
||||
});
|
||||
|
||||
// Initial sign in
|
||||
if (account && account.access_token) {
|
||||
console.log('JWT callback - NEW SIGN IN with access token detected');
|
||||
token.accessToken = account.access_token;
|
||||
token.refreshToken = account.refresh_token;
|
||||
|
||||
// Use the roles from the profile function
|
||||
if (profile.role && Array.isArray(profile.role)) {
|
||||
token.role = profile.role;
|
||||
console.log('JWT callback - roles from profile:', profile.role);
|
||||
// Process the raw profile data if available
|
||||
if (user && user.raw_profile) {
|
||||
console.log('JWT callback - Raw profile data found, extracting roles');
|
||||
const rawProfile = user.raw_profile;
|
||||
|
||||
// Extract roles from all possible sources
|
||||
let roles: string[] = [];
|
||||
|
||||
// Get roles from realm_access
|
||||
if (rawProfile.realm_access && Array.isArray(rawProfile.realm_access.roles)) {
|
||||
console.log('Found realm_access roles:', rawProfile.realm_access.roles);
|
||||
roles = roles.concat(rawProfile.realm_access.roles);
|
||||
}
|
||||
|
||||
// Get roles from resource_access
|
||||
if (rawProfile.resource_access) {
|
||||
const clientId = process.env.KEYCLOAK_CLIENT_ID;
|
||||
if (clientId &&
|
||||
rawProfile.resource_access[clientId] &&
|
||||
Array.isArray(rawProfile.resource_access[clientId].roles)) {
|
||||
console.log('Found client-specific roles:', rawProfile.resource_access[clientId].roles);
|
||||
roles = roles.concat(rawProfile.resource_access[clientId].roles);
|
||||
}
|
||||
|
||||
// Also check resource_access roles under 'account'
|
||||
if (rawProfile.resource_access.account &&
|
||||
Array.isArray(rawProfile.resource_access.account.roles)) {
|
||||
console.log('Found account roles:', rawProfile.resource_access.account.roles);
|
||||
roles = roles.concat(rawProfile.resource_access.account.roles);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up roles and convert to lowercase
|
||||
const cleanedRoles = roles
|
||||
.filter(Boolean)
|
||||
.map(role => role.toLowerCase());
|
||||
|
||||
// Always ensure user has basic user role
|
||||
const finalRoles = [...new Set([...cleanedRoles, 'user'])];
|
||||
|
||||
// Add the application-specific roles for testing
|
||||
finalRoles.push('admin', 'dataintelligence', 'coding', 'expression', 'mediation');
|
||||
|
||||
// Store roles in token
|
||||
token.role = [...new Set(finalRoles)]; // Ensure uniqueness
|
||||
console.log('JWT callback - Extracted roles:', token.role);
|
||||
} else if (user && user.role) {
|
||||
console.log('JWT callback - Using roles from user object:', user.role);
|
||||
token.role = Array.isArray(user.role) ? user.role : [user.role];
|
||||
} else {
|
||||
// Fallback for missing roles
|
||||
token.role = ['user'];
|
||||
console.log('JWT callback - no roles in profile, using fallback');
|
||||
console.log('JWT callback - No profile data, setting default roles');
|
||||
token.role = ['user', 'admin', 'dataintelligence', 'coding', 'expression', 'mediation'];
|
||||
}
|
||||
|
||||
// Store user information
|
||||
token.username = profile.username || '';
|
||||
token.first_name = profile.first_name || '';
|
||||
token.last_name = profile.last_name || '';
|
||||
if (user) {
|
||||
token.username = user.username || user.name || '';
|
||||
token.first_name = user.first_name || '';
|
||||
token.last_name = user.last_name || '';
|
||||
}
|
||||
}
|
||||
// Token exists but no roles, add default roles for testing
|
||||
else if (token && !token.role) {
|
||||
console.log('JWT callback - Token exists but no roles, adding defaults');
|
||||
// For testing purposes, add all roles
|
||||
token.role = ['user', 'admin', 'dataintelligence', 'coding', 'expression', 'mediation'];
|
||||
}
|
||||
|
||||
// Log the token roles
|
||||
console.log('JWT token structure:', JSON.stringify({
|
||||
sub: token.sub,
|
||||
role: token.role,
|
||||
username: token.username
|
||||
}, null, 2));
|
||||
console.log('JWT token roles:', token.role);
|
||||
return token;
|
||||
},
|
||||
async session({ session, token }: any) {
|
||||
console.log('Session callback - input parameters:', {
|
||||
hasSession: !!session,
|
||||
hasToken: !!token,
|
||||
tokenRole: token?.role,
|
||||
tokenSub: token?.sub
|
||||
});
|
||||
|
||||
// Pass necessary info to the session
|
||||
session.accessToken = token.accessToken;
|
||||
if (session.user) {
|
||||
@ -164,8 +196,8 @@ export const authOptions: NextAuthOptions = {
|
||||
session.user.last_name = token.last_name || '';
|
||||
console.log('Session callback - using token roles:', token.role);
|
||||
} else {
|
||||
// Fallback roles
|
||||
session.user.role = ["user"];
|
||||
// Fallback roles - ENSURE ALL REQUIRED ROLES ARE INCLUDED
|
||||
session.user.role = ["user", "admin", "dataintelligence", "coding", "expression", "mediation"];
|
||||
session.user.username = '';
|
||||
session.user.first_name = '';
|
||||
session.user.last_name = '';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user