diff --git a/app/api/auth/[...nextauth]/route.ts b/app/api/auth/[...nextauth]/route.ts index 7fc5034b..7f846362 100644 --- a/app/api/auth/[...nextauth]/route.ts +++ b/app/api/auth/[...nextauth]/route.ts @@ -60,6 +60,8 @@ export const authOptions: NextAuthOptions = { clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "", issuer: process.env.KEYCLOAK_ISSUER || "", profile(profile: any) { + console.log("Raw Keycloak profile:", profile); + // Just return a simple profile with required fields return { id: profile.sub, @@ -69,7 +71,7 @@ export const authOptions: NextAuthOptions = { username: profile.preferred_username || profile.email?.split('@')[0] || '', first_name: profile.given_name || '', last_name: profile.family_name || '', - role: ['user'], + role: profile.realm_access?.roles || ['user'], // Store raw profile data for later processing raw_profile: profile }; @@ -97,6 +99,7 @@ export const authOptions: NextAuthOptions = { // Get roles from realm_access if (rawProfile.realm_access && Array.isArray(rawProfile.realm_access.roles)) { roles = roles.concat(rawProfile.realm_access.roles); + console.log("Roles from realm_access:", rawProfile.realm_access.roles); } // Get roles from resource_access @@ -106,12 +109,14 @@ export const authOptions: NextAuthOptions = { rawProfile.resource_access[clientId] && Array.isArray(rawProfile.resource_access[clientId].roles)) { roles = roles.concat(rawProfile.resource_access[clientId].roles); + console.log("Roles from resource_access[clientId]:", rawProfile.resource_access[clientId].roles); } // Also check resource_access roles under 'account' if (rawProfile.resource_access.account && Array.isArray(rawProfile.resource_access.account.roles)) { roles = roles.concat(rawProfile.resource_access.account.roles); + console.log("Roles from resource_access.account:", rawProfile.resource_access.account.roles); } } @@ -119,17 +124,22 @@ export const authOptions: NextAuthOptions = { const cleanedRoles = roles .filter(Boolean) .map(role => role.toLowerCase()); + + console.log("Cleaned raw Keycloak roles:", cleanedRoles); // Always ensure user has basic user role const finalRoles = [...new Set([...cleanedRoles, 'user'])]; // Map Keycloak roles to application roles token.role = mapToApplicationRoles(finalRoles); + console.log("Mapped application roles:", token.role); } else if (user && user.role) { token.role = Array.isArray(user.role) ? user.role : [user.role]; + console.log("Using user.role directly:", token.role); } else { // Default roles if no profile data available token.role = ['user']; + console.log("Using default 'user' role only"); } // Store user information @@ -142,6 +152,7 @@ export const authOptions: NextAuthOptions = { // Token exists but no roles, add default user role else if (token && !token.role) { token.role = ['user']; + console.log("Adding default 'user' role to existing token"); } return token; @@ -158,12 +169,14 @@ export const authOptions: NextAuthOptions = { session.user.username = token.username || ''; session.user.first_name = token.first_name || ''; session.user.last_name = token.last_name || ''; + console.log("Session updated with roles from token:", token.role); } else { // Fallback roles session.user.role = ["user"]; session.user.username = ''; session.user.first_name = ''; session.user.last_name = ''; + console.log("Session using fallback 'user' role only"); } } return session; diff --git a/components/main-nav.tsx b/components/main-nav.tsx index 2c57f556..bdf78646 100644 --- a/components/main-nav.tsx +++ b/components/main-nav.tsx @@ -52,8 +52,12 @@ export function MainNav() { const { data: session, status } = useSession(); const [userStatus, setUserStatus] = useState<'online' | 'busy' | 'away'>('online'); - console.log("Session:", session); - console.log("Status:", status); + console.log("Session:", { + authenticated: status === "authenticated", + status, + user: session?.user, + roles: session?.user?.role + }); // Updated function to get user initials const getUserInitials = () => { @@ -191,26 +195,30 @@ export function MainNav() { title: "ShowCase", icon: Lightbulb, href: '/showcase', - requiredRoles: ["Expression"], + requiredRoles: ["expression"], }, { title: "Equipes", icon: UserCog, href: '/equipes', - requiredRoles: ["Admin", "Entrepreneurship"], + requiredRoles: ["admin", "entrepreneurship"], }, { title: "TheMessage", icon: Mail, href: '/the-message', - requiredRoles: ["Mediation", "Expression"], + requiredRoles: ["mediation", "expression"], }, ]; // Get visible menu items based on user roles const visibleMenuItems = [ ...baseMenuItems, - ...roleSpecificItems.filter(item => hasRole(item.requiredRoles)) + ...roleSpecificItems.filter(item => { + const result = hasRole(item.requiredRoles); + console.log(`Menu item '${item.title}' with required roles [${item.requiredRoles.join(', ')}] is ${result ? 'visible' : 'hidden'}`); + return result; + }) ]; // Format current date and time diff --git a/components/sidebar.tsx b/components/sidebar.tsx index f9d4d91d..bd720088 100644 --- a/components/sidebar.tsx +++ b/components/sidebar.tsx @@ -1,7 +1,7 @@ "use client"; import type React from "react"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { cn } from "@/lib/utils"; import { @@ -45,9 +45,19 @@ interface MenuItem { } export function Sidebar({ isOpen, onClose }: SidebarProps) { - const { data: session, status } = useSession(); const router = useRouter(); const pathname = usePathname(); + const { data: session, status } = useSession(); + + // Log session status whenever it changes + useEffect(() => { + console.log("Sidebar Session:", { + authenticated: status === "authenticated", + status, + user: session?.user, + roles: session?.user?.role + }); + }, [session, status]); // Debug session data console.log('Session state:', { @@ -80,7 +90,12 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { } const userRoles = Array.isArray(session.user.role) ? session.user.role : [session.user.role]; - const cleanUserRoles = userRoles.map(role => role.toLowerCase()); + // Clean up user roles by removing prefixes and converting to lowercase + const cleanUserRoles = userRoles.map(role => + role.replace(/^[\/]/, '') // Remove leading slash + .replace(/^ROLE_/, '') // Remove ROLE_ prefix + .toLowerCase() + ); console.log('Debug roles:', { rawUserRoles: session.user.role, @@ -199,7 +214,13 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) { // Combine base items with role-specific items based on user roles const visibleMenuItems = [ ...baseMenuItems, - ...roleSpecificItems.filter(item => hasRole(item.requiredRole)) + ...roleSpecificItems.filter(item => { + const result = hasRole(item.requiredRole); + console.log(`Sidebar item '${item.title}' with required role ${Array.isArray(item.requiredRole) ? + '[' + item.requiredRole.join(', ') + ']' : + item.requiredRole} is ${result ? 'visible' : 'hidden'}`); + return result; + }) ]; const handleNavigation = (href: string, external?: boolean) => {