diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 8b9a19df..3a91f648 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -88,6 +88,11 @@ export const authOptions: NextAuthOptions = { clientSecret: getRequiredEnvVar("KEYCLOAK_CLIENT_SECRET"), issuer: getRequiredEnvVar("KEYCLOAK_ISSUER"), profile(profile) { + // Clean up roles by removing ROLE_ prefix and converting to lowercase + const cleanRoles = (profile.roles ?? []).map(role => + role.replace(/^ROLE_/, '').toLowerCase() + ); + return { id: profile.sub, name: profile.name ?? profile.preferred_username, @@ -95,7 +100,7 @@ export const authOptions: NextAuthOptions = { first_name: profile.given_name ?? '', last_name: profile.family_name ?? '', username: profile.preferred_username ?? profile.email?.split('@')[0] ?? '', - role: profile.groups ?? [], + role: cleanRoles, } }, }), @@ -108,11 +113,16 @@ export const authOptions: NextAuthOptions = { async jwt({ token, account, profile }) { if (account && profile) { const keycloakProfile = profile as KeycloakProfile; + // Clean up roles by removing ROLE_ prefix and converting to lowercase + const cleanRoles = (keycloakProfile.roles ?? []).map(role => + role.replace(/^ROLE_/, '').toLowerCase() + ); + token.accessToken = account.access_token ?? ''; token.refreshToken = account.refresh_token ?? ''; token.accessTokenExpires = account.expires_at ?? 0; token.sub = keycloakProfile.sub; - token.role = keycloakProfile.roles ?? []; + token.role = cleanRoles; token.username = keycloakProfile.preferred_username ?? ''; token.first_name = keycloakProfile.given_name ?? ''; token.last_name = keycloakProfile.family_name ?? ''; diff --git a/components/sidebar.tsx b/components/sidebar.tsx index e77b59b6..5b48a724 100644 --- a/components/sidebar.tsx +++ b/components/sidebar.tsx @@ -76,18 +76,7 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { } const userRoles = Array.isArray(session.user.role) ? session.user.role : [session.user.role]; - console.log('Raw user roles:', userRoles); - - // Clean up user roles by removing prefixes and converting to lowercase for comparison - const cleanUserRoles = userRoles.map(role => { - const cleaned = role - .replace(/^[\/]/, '') // Remove leading slash - .replace(/^ROLE_/, '') // Remove ROLE_ prefix - .toLowerCase(); - console.log('Cleaning role:', { original: role, cleaned }); - return cleaned; - }); - console.log('Clean user roles:', cleanUserRoles); + console.log('User roles:', userRoles); // If requiredRole is an array, check if user has any of the roles if (Array.isArray(requiredRole)) { @@ -95,10 +84,10 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { console.log('Checking multiple roles:', { requiredRoles: requiredRole, cleanRequiredRoles, - hasAnyRole: cleanRequiredRoles.some(role => cleanUserRoles.includes(role)), - matchingRoles: cleanRequiredRoles.filter(role => cleanUserRoles.includes(role)) + hasAnyRole: cleanRequiredRoles.some(role => userRoles.includes(role)), + matchingRoles: cleanRequiredRoles.filter(role => userRoles.includes(role)) }); - return cleanRequiredRoles.some(role => cleanUserRoles.includes(role)); + return cleanRequiredRoles.some(role => userRoles.includes(role)); } // For single role requirement @@ -106,9 +95,9 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { console.log('Checking single role:', { requiredRole, cleanRequiredRole, - hasRole: cleanUserRoles.includes(cleanRequiredRole) + hasRole: userRoles.includes(cleanRequiredRole) }); - return cleanUserRoles.includes(cleanRequiredRole); + return userRoles.includes(cleanRequiredRole); }; // Base menu items (available for everyone)