import { createContext, useContext, useEffect, useState, type ReactNode } from 'react'; import { getUser, login, logout, userManager, type User } from './oidc'; import { triggerLoginRedirect } from './sessionRedirect'; import { Permission, mapGroupsToPermissions } from './permissions'; interface AuthContextType { user: User | null; isAuthenticated: boolean; isLoading: boolean; permissions: Permission[]; hasPermission: (permission: Permission) => boolean; login: () => Promise; logout: () => Promise; } const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(null); const [permissions, setPermissions] = useState([]); const [isLoading, setIsLoading] = useState(true); const updatePermissions = (u: User | null) => { if (!u) { setPermissions([]); return; } const groups = (u.profile as any).groups as string[] | undefined; setPermissions(mapGroupsToPermissions(groups)); }; useEffect(() => { getUser() .then((u) => { setUser(u); updatePermissions(u); }) .finally(() => setIsLoading(false)); const onUserLoaded = (u: User) => { console.log('OIDC: User loaded/renewed'); setUser(u); updatePermissions(u); }; const onUserUnloaded = () => { console.log('OIDC: User unloaded'); setUser(null); updatePermissions(null); }; const onSilentRenewError = (err: Error) => { console.error('OIDC: Silent renew failed:', err); if (/login_required|interaction_required|invalid_grant/.test(err.message ?? '')) { setUser(null); updatePermissions(null); triggerLoginRedirect(); } }; userManager.events.addUserLoaded(onUserLoaded); userManager.events.addUserUnloaded(onUserUnloaded); userManager.events.addSilentRenewError(onSilentRenewError); return () => { userManager.events.removeUserLoaded(onUserLoaded); userManager.events.removeUserUnloaded(onUserUnloaded); userManager.events.removeSilentRenewError(onSilentRenewError); }; }, []); const hasPermission = (permission: Permission) => { if (permissions.includes(Permission.MANAGE_ALL)) return true; return permissions.includes(permission); }; return ( {children} ); } export function useAuth(): AuthContextType { const ctx = useContext(AuthContext); if (!ctx) throw new Error('useAuth must be used within AuthProvider'); return ctx; }