/** * Zitadel + generic role-based access control helpers. * * Supports Zitadel IAM role claims (`urn:zitadel:iam:org:project:roles`), * generic `roles` arrays, and object-based role maps. * * If auth provider uses a different claim format, extend `hasRole` * rather than forking this module. */ export function hasRole(profile: Record | null | undefined, role: string): boolean { if (!profile) return false; if (!role || typeof role !== 'string') return false; const zitadelRoles = profile['urn:zitadel:iam:org:project:roles']; if (zitadelRoles && typeof zitadelRoles === 'object') { try { if (zitadelRoles !== null && !Array.isArray(zitadelRoles) && Object.hasOwn(zitadelRoles, role)) { return true; } } catch { // Continue to other role formats when host objects reject inspection. } } const rolesArray = profile.roles; if (Array.isArray(rolesArray)) { return rolesArray.includes(role); } if (rolesArray && typeof rolesArray === 'object' && !Array.isArray(rolesArray)) { try { if (rolesArray !== null) { return Object.hasOwn(rolesArray, role); } } catch { // Fall through. } } return false; } /** Collect every role name from a profile — Zitadel IAM roles, `roles` arrays, and object-based role maps — into a deduplicated `string[]`. */ export function getRoles(profile: Record | null | undefined): string[] { if (!profile) return []; const roles = new Set(); const zitadelRoles = profile['urn:zitadel:iam:org:project:roles']; if (zitadelRoles && typeof zitadelRoles === 'object' && zitadelRoles !== null && !Array.isArray(zitadelRoles)) { try { for (const key of Object.keys(zitadelRoles)) { roles.add(key); } } catch { // Ignore host objects that reject key enumeration. } } const rolesArray = profile.roles; if (Array.isArray(rolesArray)) { rolesArray.forEach((role) => { if (typeof role === 'string') roles.add(role); }); } if (rolesArray && typeof rolesArray === 'object' && rolesArray !== null && !Array.isArray(rolesArray)) { try { for (const key of Object.keys(rolesArray)) { roles.add(key); } } catch { // Ignore host objects that reject key enumeration. } } return Array.from(roles); }