Claude-skill-registry Enterprise RBAC Models
Comprehensive guide to implementing Role-Based Access Control for enterprise applications with hierarchical roles, custom permissions, and multi-level access
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/enterprise-rbac-models" ~/.claude/skills/majiayu000-claude-skill-registry-enterprise-rbac-models && rm -rf "$T"
skills/data/enterprise-rbac-models/SKILL.mdEnterprise RBAC Models
What is RBAC?
Role-Based Access Control (RBAC): Users → Roles → Permissions
Model
Users: John, Jane, Bob Roles: Admin, Manager, Member, Viewer Permissions: create_project, delete_user, view_reports John → Admin → {create_project, delete_user, view_reports, ...} Jane → Manager → {create_project, view_reports} Bob → Viewer → {view_reports}
vs ACL (Access Control List)
ACL: Direct user permissions
John can create_project John can delete_user John can view_reports (Doesn't scale!)
RBAC: Role-based permissions
John is Admin Admin can create_project, delete_user, view_reports (Scalable!)
vs ABAC (Attribute-Based Access Control)
ABAC: Policy-based decisions
IF user.department == "Engineering" AND resource.sensitivity == "low" THEN allow access
When to Use:
- RBAC: Most applications (simple, scalable)
- ACL: Very simple apps (few users, few permissions)
- ABAC: Complex policies (government, healthcare)
Why Enterprises Need RBAC
1. Scalable
Without RBAC:
New employee joins → Assign 50 individual permissions manually → Error-prone, time-consuming
With RBAC:
New employee joins → Assign "Member" role → Automatically gets all member permissions
2. Auditable
Questions:
- Who has admin access?
- What can this user do?
- When did they get this permission?
RBAC Provides:
- List all users with "Admin" role
- List all permissions for "Manager" role
- Audit log of role assignments
3. Least Privilege Principle
Principle: Users should have minimum permissions needed
RBAC Enforces:
- Default role: Viewer (read-only)
- Promote to Member (can edit own)
- Promote to Manager (can edit all)
- Promote to Admin (full control)
4. Segregation of Duties
Principle: No single user should have too much power
Example:
- User can create invoice (Member)
- Different user must approve invoice (Manager)
- Prevents fraud
RBAC Components
1. Users
Definition: People or service accounts
Examples:
- john.doe@example.com (person)
- api-service@example.com (service account)
- github-bot@example.com (bot)
2. Roles
Definition: Named collection of permissions
Examples:
- Admin (full control)
- Manager (create, edit, delete)
- Member (create, edit own)
- Viewer (read-only)
3. Permissions
Definition: Specific actions on resources
Format:
resource:action
Examples:
project:createuser:deletereport:viewbilling:manage
4. Resources
Definition: Things users act on
Examples:
- Projects
- Files
- Reports
- Users
- Settings
Common Enterprise Roles
Owner/Admin
Permissions: Full control
- project:* - user:* - billing:* - settings:*
Use Case: Founder, CTO, IT admin
Manager/Editor
Permissions: Create, edit, delete (but not billing/settings)
- project:create - project:edit - project:delete - user:invite - report:view
Use Case: Team lead, project manager
Member/Contributor
Permissions: Create, edit own
- project:create - project:edit_own - file:upload - report:view
Use Case: Engineer, designer, analyst
Viewer/Reader
Permissions: Read-only
- project:view - file:view - report:view
Use Case: Stakeholder, auditor, contractor
Billing Admin
Permissions: Manage billing only
- billing:view - billing:manage - invoice:download
Use Case: Finance team
Support
Permissions: Limited access for support
- user:view - project:view - logs:view
Use Case: Customer support team
Permission Naming Conventions
Format 1: resource:action
project:create project:edit project:delete project:view user:create user:edit user:delete user:view
Pros: Clear, consistent, easy to parse
Format 2: action_resource
create_project edit_project delete_project view_project
Pros: Reads like English
Recommendation: Use
resource:action (more common)
Wildcard Permissions
project:* (all project permissions) *:view (view all resources) *:* (all permissions, superuser)
Hierarchical Roles
Inheritance
Model:
Admin inherits all permissions of Manager Manager inherits all permissions of Member Member inherits all permissions of Viewer
Example:
Viewer: - project:view - file:view Member (inherits Viewer): - project:view - file:view - project:create - file:upload Manager (inherits Member): - project:view - file:view - project:create - file:upload - project:delete - user:invite Admin (inherits Manager): - project:view - file:view - project:create - file:upload - project:delete - user:invite - user:delete - billing:manage - settings:*
Implementation
const roleHierarchy = { viewer: [], member: ['viewer'], manager: ['member'], admin: ['manager'] }; function getAllPermissions(role) { const permissions = new Set(rolePermissions[role]); // Add inherited permissions for (const parentRole of roleHierarchy[role]) { const parentPerms = getAllPermissions(parentRole); parentPerms.forEach(p => permissions.add(p)); } return Array.from(permissions); }
Custom Roles (Enterprise Feature)
What Are Custom Roles?
Definition: Customer defines their own roles with specific permissions
Example:
Customer creates "Auditor" role: - project:view - file:view - logs:view - report:export (Read-only + export)
Database Schema
CREATE TABLE custom_roles ( id UUID PRIMARY KEY, tenant_id UUID NOT NULL, name VARCHAR(255) NOT NULL, description TEXT, created_at TIMESTAMP DEFAULT NOW() ); CREATE TABLE custom_role_permissions ( role_id UUID REFERENCES custom_roles(id), permission VARCHAR(255) NOT NULL, PRIMARY KEY (role_id, permission) );
Implementation
// Create custom role app.post('/api/roles', async (req, res) => { const { name, description, permissions } = req.body; const role = await db.customRoles.create({ tenantId: req.user.tenantId, name, description }); for (const permission of permissions) { await db.customRolePermissions.create({ roleId: role.id, permission }); } res.json(role); }); // Assign custom role to user app.post('/api/users/:userId/roles', async (req, res) => { const { roleId } = req.body; await db.userRoles.create({ userId: req.params.userId, roleId }); res.json({ success: true }); });
Multi-Level RBAC
Organization Level
Scope: Entire organization
Roles:
- Org Owner (full control over org)
- Org Admin (manage users, billing)
- Org Member (access to all projects)
Project/Workspace Level
Scope: Specific project or workspace
Roles:
- Project Admin (full control over project)
- Project Member (can edit project)
- Project Viewer (can view project)
Resource Level
Scope: Specific resource (document, file)
Roles:
- Document Owner (full control over document)
- Document Editor (can edit document)
- Document Viewer (can view document)
Example
John is: - Org Member (organization level) - Project Admin in "Website Redesign" (project level) - Document Owner of "Design Spec" (resource level) Permissions: - Can view all org projects (org member) - Can manage "Website Redesign" project (project admin) - Can delete "Design Spec" document (document owner)
RBAC Implementation Patterns
Database Schema
CREATE TABLE users ( id UUID PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, name VARCHAR(255) ); CREATE TABLE roles ( id UUID PRIMARY KEY, name VARCHAR(50) UNIQUE NOT NULL, description TEXT ); CREATE TABLE permissions ( id UUID PRIMARY KEY, name VARCHAR(100) UNIQUE NOT NULL, description TEXT ); CREATE TABLE user_roles ( user_id UUID REFERENCES users(id), role_id UUID REFERENCES roles(id), PRIMARY KEY (user_id, role_id) ); CREATE TABLE role_permissions ( role_id UUID REFERENCES roles(id), permission_id UUID REFERENCES permissions(id), PRIMARY KEY (role_id, permission_id) );
Permission Checking
async function hasPermission(userId, permission, resourceId = null) { // Get user's roles const userRoles = await db.userRoles .where({ userId }) .join('roles', 'roles.id', 'user_roles.role_id') .select('roles.name'); // Get permissions for those roles const rolePermissions = await db.rolePermissions .whereIn('role_id', userRoles.map(r => r.id)) .join('permissions', 'permissions.id', 'role_permissions.permission_id') .select('permissions.name'); // Check if user has permission const hasPermission = rolePermissions.some(p => p.name === permission || p.name === permission.split(':')[0] + ':*' ); // Check resource-level permissions (if applicable) if (resourceId) { const isOwner = await db.resources.findOne({ id: resourceId, ownerId: userId }); if (isOwner) return true; } return hasPermission; }
Middleware for API Routes
function requirePermission(permission) { return async (req, res, next) => { const hasPermission = await hasPermission(req.user.id, permission); if (!hasPermission) { return res.status(403).json({ error: 'Forbidden', message: `You don't have permission: ${permission}` }); } next(); }; } // Usage app.delete('/api/projects/:id', requirePermission('project:delete'), async (req, res) => { // Delete project } );
UI Components
function CanAccess({ permission, children }) { const { user } = useAuth(); const hasPermission = usePermission(user.id, permission); if (!hasPermission) return null; return children; } // Usage <CanAccess permission="project:delete"> <button onClick={deleteProject}>Delete Project</button> </CanAccess>
RBAC with Teams
Model
Users belong to Teams Teams have Roles in Workspaces Users inherit permissions from Team Roles
Example
Team: Engineering Members: John, Jane, Bob Workspace: Website Redesign Engineering team has "Editor" role Result: - John can edit Website Redesign (via Engineering team) - Jane can edit Website Redesign (via Engineering team) - Bob can edit Website Redesign (via Engineering team)
Database Schema
CREATE TABLE teams ( id UUID PRIMARY KEY, name VARCHAR(255) NOT NULL ); CREATE TABLE team_members ( team_id UUID REFERENCES teams(id), user_id UUID REFERENCES users(id), PRIMARY KEY (team_id, user_id) ); CREATE TABLE team_workspace_roles ( team_id UUID REFERENCES teams(id), workspace_id UUID REFERENCES workspaces(id), role_id UUID REFERENCES roles(id), PRIMARY KEY (team_id, workspace_id) );
Permission Checking
async function hasPermission(userId, permission, workspaceId) { // Check direct user roles const directPermissions = await getUserPermissions(userId, workspaceId); // Check team roles const teams = await db.teamMembers.where({ userId }); const teamPermissions = await getTeamPermissions(teams, workspaceId); const allPermissions = [...directPermissions, ...teamPermissions]; return allPermissions.includes(permission); }
RBAC with SSO
Map SSO Groups to Application Roles
SAML Assertion:
<saml:Attribute Name="groups"> <saml:AttributeValue>Admins</saml:AttributeValue> <saml:AttributeValue>Engineering</saml:AttributeValue> </saml:Attribute>
Mapping Configuration:
const ssoGroupRoleMapping = { 'Admins': 'admin', 'Engineering': 'member', 'Sales': 'member', 'Executives': 'viewer' }; async function handleSSOLogin(assertion) { const ssoGroups = assertion.attributes.groups || []; const roles = ssoGroups .map(group => ssoGroupRoleMapping[group]) .filter(role => role !== undefined); // Assign roles to user await db.userRoles.deleteWhere({ userId: user.id }); for (const roleName of roles) { const role = await db.roles.findOne({ name: roleName }); await db.userRoles.create({ userId: user.id, roleId: role.id }); } }
Override SSO-Assigned Roles (If Allowed)
Option 1: SSO roles are authoritative (can't override)
// Always sync roles from SSO await syncRolesFromSSO(user, ssoGroups);
Option 2: SSO roles + manual roles
// Keep manual roles, add SSO roles const manualRoles = await getManualRoles(user.id); const ssoRoles = mapSSOGroups(ssoGroups); const allRoles = [...manualRoles, ...ssoRoles];
Permission Inheritance
Org Admin → Project Admin
Rule: Org admin automatically has admin access to all projects
Implementation:
async function hasPermission(userId, permission, projectId) { // Check if user is org admin const isOrgAdmin = await db.userRoles.findOne({ userId, role: 'org_admin' }); if (isOrgAdmin) return true; // Org admin can do anything // Check project-level permissions const projectRole = await db.projectRoles.findOne({ userId, projectId }); return projectRole && hasPermissionForRole(projectRole.role, permission); }
Project Member → Resource Viewer
Rule: Project member can view all resources in project
Implementation:
async function canViewResource(userId, resourceId) { const resource = await db.resources.findOne({ id: resourceId }); const projectMember = await db.projectMembers.findOne({ userId, projectId: resource.projectId }); return projectMember !== null; }
Conditional Permissions
Resource Owner
Rule: Can edit own documents (even if not editor role)
Implementation:
async function canEditDocument(userId, documentId) { const document = await db.documents.findOne({ id: documentId }); // Owner can always edit if (document.ownerId === userId) return true; // Check role-based permissions return await hasPermission(userId, 'document:edit'); }
Time-Based
Rule: Temporary access (expires after 7 days)
Implementation:
async function hasTemporaryAccess(userId, resourceId) { const access = await db.temporaryAccess.findOne({ userId, resourceId, expiresAt: { $gt: new Date() } // Not expired }); return access !== null; }
Approval-Based
Rule: Request access, admin approves
Implementation:
// Request access app.post('/api/access-requests', async (req, res) => { const { resourceId, reason } = req.body; const request = await db.accessRequests.create({ userId: req.user.id, resourceId, reason, status: 'pending' }); // Notify admins await notifyAdmins(request); res.json(request); }); // Approve access app.post('/api/access-requests/:id/approve', async (req, res) => { const request = await db.accessRequests.findOne({ id: req.params.id }); // Grant temporary access (7 days) await db.temporaryAccess.create({ userId: request.userId, resourceId: request.resourceId, expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) }); request.status = 'approved'; await request.save(); res.json(request); });
RBAC Testing
Test Each Role
describe('RBAC', () => { test('Admin can delete projects', async () => { const admin = await createUser({ role: 'admin' }); const canDelete = await hasPermission(admin.id, 'project:delete'); expect(canDelete).toBe(true); }); test('Member cannot delete projects', async () => { const member = await createUser({ role: 'member' }); const canDelete = await hasPermission(member.id, 'project:delete'); expect(canDelete).toBe(false); }); test('Viewer can view projects', async () => { const viewer = await createUser({ role: 'viewer' }); const canView = await hasPermission(viewer.id, 'project:view'); expect(canView).toBe(true); }); });
Test Permission Inheritance
test('Manager inherits Member permissions', async () => { const manager = await createUser({ role: 'manager' }); // Manager should have member permissions expect(await hasPermission(manager.id, 'project:create')).toBe(true); expect(await hasPermission(manager.id, 'project:edit')).toBe(true); // Plus manager-specific permissions expect(await hasPermission(manager.id, 'user:invite')).toBe(true); });
Test API Permissions
test('DELETE /api/projects requires project:delete permission', async () => { const member = await createUser({ role: 'member' }); const token = await generateToken(member); const response = await request(app) .delete('/api/projects/123') .set('Authorization', `Bearer ${token}`); expect(response.status).toBe(403); expect(response.body.error).toBe('Forbidden'); });
Test UI Shows/Hides Correctly
test('Delete button hidden for members', () => { const member = { role: 'member' }; const { queryByText } = render(<ProjectPage user={member} />); expect(queryByText('Delete Project')).toBeNull(); }); test('Delete button visible for admins', () => { const admin = { role: 'admin' }; const { getByText } = render(<ProjectPage user={admin} />); expect(getByText('Delete Project')).toBeInTheDocument(); });
RBAC Audit Logging
Log Permission Changes
// Log role assignment app.post('/api/users/:userId/roles', async (req, res) => { const { roleId } = req.body; await db.userRoles.create({ userId: req.params.userId, roleId }); // Audit log await db.auditLogs.create({ action: 'role_assigned', actorId: req.user.id, targetUserId: req.params.userId, roleId, timestamp: new Date() }); res.json({ success: true }); });
Log Access Attempts
async function hasPermission(userId, permission, resourceId) { const allowed = await checkPermission(userId, permission, resourceId); // Log access attempt await db.accessLogs.create({ userId, permission, resourceId, allowed, timestamp: new Date() }); return allowed; }
Regular Access Reviews
// Generate access review report app.get('/api/reports/access-review', async (req, res) => { const users = await db.users.all(); const report = []; for (const user of users) { const roles = await db.userRoles.where({ userId: user.id }); const permissions = await getAllPermissions(roles); report.push({ user: user.email, roles: roles.map(r => r.name), permissions, lastLogin: user.lastLoginAt }); } res.json(report); });
Tools and Libraries
Casbin (Policy Engine)
Features:
- Policy-based access control
- Supports RBAC, ABAC, ACL
- Multiple languages (Go, Node.js, Python, Java)
Example:
const casbin = require('casbin'); const enforcer = await casbin.newEnforcer('model.conf', 'policy.csv'); // Check permission const allowed = await enforcer.enforce('john', 'project', 'delete');
Oso (Authorization Library)
Features:
- Declarative policies (Polar language)
- Supports RBAC, ABAC
- Python, Ruby, Node.js, Java
Example:
from oso import Oso oso = Oso() oso.load_files(["policy.polar"]) # Check permission allowed = oso.is_allowed(user, "delete", project)
AWS IAM (Inspiration)
Concepts:
- Users, Groups, Roles, Policies
- Policy documents (JSON)
- Resource-based policies
Learn From: AWS IAM design patterns
Custom Implementation
When to Use: Most applications (RBAC is simple enough to implement)
Benefits:
- Full control
- No external dependencies
- Tailored to your needs
Real RBAC Models
GitHub
Roles:
- Owner (full control)
- Maintainer (manage repo, can't delete)
- Member (write access)
- Triage (manage issues)
- Read (read-only)
Levels:
- Organization level
- Repository level
Google Workspace
Roles:
- Super Admin (full control)
- Admin (manage users, settings)
- User (standard access)
Custom Roles: Yes (enterprise feature)
Salesforce
Roles:
- System Administrator (full control)
- Standard User (basic access)
- Custom roles (customer-defined)
Levels:
- Organization level
- Object level (per Salesforce object)
Summary
Quick Reference
RBAC: Users → Roles → Permissions
Components:
- Users (people, service accounts)
- Roles (Admin, Manager, Member, Viewer)
- Permissions (project:create, user:delete)
- Resources (projects, files, reports)
Common Roles:
- Owner/Admin (full control)
- Manager/Editor (create, edit, delete)
- Member/Contributor (create, edit own)
- Viewer/Reader (read-only)
Permission Format:
resource:action
Hierarchical Roles:
- Admin inherits Manager
- Manager inherits Member
- Member inherits Viewer
Multi-Level:
- Organization level
- Project/workspace level
- Resource level
Database Schema:
- users, roles, permissions
- user_roles, role_permissions
Permission Checking:
hasPermission(userId, permission, resourceId)
Middleware:
requirePermission('project:delete')
UI Components:
<CanAccess permission="project:delete"> <button>Delete</button> </CanAccess>
Testing:
- Test each role
- Test permission inheritance
- Test API permissions
- Test UI shows/hides
Tools:
- Casbin (policy engine)
- Oso (authorization library)
- Custom implementation (recommended)
Best Practices
RBAC Design Best Practices
- Principle of Least Privilege: Grant users only the minimum permissions needed to perform their job functions. Start with read-only access and escalate only when necessary.
- Role Hierarchy: Design a clear role hierarchy where higher-level roles inherit permissions from lower-level roles. This reduces duplication and simplifies management.
- Permission Granularity: Use fine-grained permissions (e.g.,
,project:create
,project:edit_own
) rather than coarse-grained ones (e.g.,project:edit_all
).project:manage - Separation of Duties: Implement role separation for critical operations. For example, different users should be able to create invoices and approve invoices to prevent fraud.
- Default Deny: Always deny access by default and explicitly grant permissions. This prevents accidental access from missing permission checks.
Implementation Best Practices
- Database Design: Use normalized schema with separate tables for users, roles, permissions, and their relationships. This allows for flexible querying and auditing.
- Permission Caching: Cache user permissions after initial lookup to avoid repeated database queries. Invalidate cache when roles or permissions change.
- Middleware Pattern: Implement permission checking as middleware in your API framework. This ensures consistent enforcement across all endpoints.
- UI Integration: Create reusable UI components (e.g.,
) that conditionally render based on user permissions. This provides a better user experience.<CanAccess> - Audit Logging: Log all permission changes and access attempts. This is essential for security audits and compliance.
Multi-Level RBAC Best Practices
- Organization-Level Roles: Define org-wide roles (Owner, Admin, Member) for administrative functions like billing and user management.
- Project-Level Roles: Define project-specific roles (Admin, Member, Viewer) for resource access within projects.
- Resource-Level Permissions: Implement resource ownership checks where users can always access resources they created, regardless of their role.
- Permission Inheritance: Ensure that org admins automatically have admin access to all projects, and project members can view all project resources.
SSO Integration Best Practices
- Group-to-Role Mapping: Map SSO groups to application roles automatically. This allows IT admins to control access through their IdP.
- JIT Provisioning: Create users on first SSO login with default roles based on their group membership.
- Role Synchronization: Sync roles from SSO on each login to ensure users always have the correct permissions.
- Override Capability: Allow manual role overrides for special cases where SSO-assigned roles need adjustment.
Testing Best Practices
- Test Each Role: Write tests for each role to verify they have expected permissions and are denied access to unauthorized resources.
- Test Inheritance: Verify that role inheritance works correctly and that higher-level roles have all permissions of lower-level roles.
- Test API Endpoints: Test that API endpoints properly enforce permissions and return appropriate error codes (403 Forbidden) for unauthorized access.
- Test UI Components: Verify that UI elements are shown/hidden based on user permissions.
- Test Edge Cases: Test resource ownership, time-based access, and approval-based access flows.
Security Best Practices
- Never Trust Client-Side: Always validate permissions on the server-side, even if UI hides certain actions.
- Secure Session Management: Use secure, HTTP-only cookies with SameSite protection to prevent session hijacking.
- Rate Limiting: Implement rate limiting on permission checks to prevent brute force attacks.
- Regular Access Reviews: Conduct quarterly reviews of who has what permissions and revoke access that is no longer needed.
- Log Suspicious Activity: Alert on repeated permission denials, access from unusual locations, or access attempts outside business hours.
Checklist
RBAC Design Checklist
- Define user types and their access requirements
- Create a clear role hierarchy with inheritance
- Design fine-grained permissions using
formatresource:action - Implement separation of duties for critical operations
- Apply principle of least privilege for all roles
- Document all roles and their permissions
Implementation Checklist
- Design normalized database schema for users, roles, permissions
- Implement permission checking function with caching
- Create middleware for API permission enforcement
- Build UI components for conditional rendering
- Implement audit logging for permission changes
- Add error handling for unauthorized access (403)
Multi-Level RBAC Checklist
- Define organization-level roles (Owner, Admin, Member)
- Define project-level roles (Admin, Member, Viewer)
- Implement resource ownership checks
- Configure permission inheritance between levels
- Test cross-level access permissions
SSO Integration Checklist
- Configure SSO group-to-role mapping
- Implement JIT provisioning for new users
- Set up role synchronization on login
- Allow manual role overrides if needed
- Test SSO login with different group memberships
Testing Checklist
- Write tests for each role's permissions
- Test role inheritance behavior
- Test API endpoint permission enforcement
- Test UI component visibility based on permissions
- Test edge cases (resource owner, time-based access)
- Run tests in CI/CD pipeline
Security Checklist
- Validate all permissions on server-side
- Use secure, HTTP-only session cookies
- Implement rate limiting on permission checks
- Set up regular access review process
- Configure alerts for suspicious activity
- Review and update permissions quarterly
Deployment Checklist
- Document RBAC model for users
- Create admin guide for role management
- Set up monitoring for permission errors
- Configure backup and restore for role data
- Train support team on common RBAC issues
- Create incident response process for permission issues