Role-Based Access Control (RBAC) - SDK Documentation
For User-Friendly RBAC Guides: See our RBAC & Permissions documentation for step-by-step instructions on managing roles and permissions through the Workspace Platform interface.
This document provides technical documentation for developers using the Workspace Platform SDK to programmatically manage Role-Based Access Control (RBAC) functionality.
The RBAC module (sdk.rbac) provides comprehensive role-based access control functionality, allowing you to manage permissions, roles, and access control for users across workspaces, teams, and resources.
Permission Checking
Single Permission Check
Check if the current user has a specific permission on a resource:
const canEdit = await sdk.rbac.checkPermission('edit', 'workspace:123');
if (canEdit) {
console.log('User can edit this workspace');
// Proceed with edit operation
} else {
console.log('Access denied');
}
Bulk Permission Check
Check multiple permissions at once for better performance:
const permissionChecks = await sdk.rbac.checkMultiplePermissions({
permissions: [
{ permission: 'read', resource: 'project:456' },
{ permission: 'write', resource: 'project:456' },
{ permission: 'delete', resource: 'project:456' },
{ permission: 'manage_members', resource: 'team:789' },
],
});
// Process results
const userPermissions = {};
permissionChecks.forEach(result => {
const key = `${result.resource}:${result.permission}`;
userPermissions[key] = result.hasPermission;
});
console.log('User permissions:', userPermissions);
Role Management
Get All Roles
const roles = await sdk.rbac.getRoles();
roles.forEach(role => {
console.log(`${role.name}: ${role.description}`);
});
Get Single Role
const role = await sdk.rbac.getRole('admin-role-id');
if (role) {
console.log(`Role: ${role.name}`);
console.log(`Description: ${role.description}`);
console.log(`Created: ${role.createdAt}`);
}
Create Role
const newRole = await sdk.rbac.createRole({
name: 'Project Manager',
description: 'Can manage projects and assign team members',
});
console.log(`Created role: ${newRole.id}`);
Update Role
const updatedRole = await sdk.rbac.updateRole('role-id', {
name: 'Senior Project Manager',
description: 'Enhanced project management with budget oversight',
});
console.log(`Updated role: ${updatedRole.name}`);
Delete Role
const deleted = await sdk.rbac.deleteRole('role-id');
console.log(`Role deleted: ${deleted}`);
Permission Management
Get All Permissions
// Get all permissions
const allPermissions = await sdk.rbac.getPermissions();
// Get permissions by category
const adminPermissions = await sdk.rbac.getPermissions('admin');
const basicPermissions = await sdk.rbac.getPermissions('basic');
console.log(`Found ${allPermissions.length} total permissions`);
Get Single Permission
const permission = await sdk.rbac.getPermission('read-permission-id');
if (permission) {
console.log(`Permission: ${permission.name}`);
console.log(`Category: ${permission.category}`);
console.log(`Description: ${permission.description}`);
}
Create Permission
const newPermission = await sdk.rbac.createPermission({
name: 'export_data',
description: 'Allow user to export data from the system',
category: 'data',
});
console.log(`Created permission: ${newPermission.id}`);
Update Permission
const updatedPermission = await sdk.rbac.updatePermission('permission-id', {
name: 'export_all_data',
description: 'Allow user to export all data including sensitive information',
category: 'admin',
});
Delete Permission
const deleted = await sdk.rbac.deletePermission('permission-id');
console.log(`Permission deleted: ${deleted}`);
User-Role Assignments
Assign Role to User
const userRole = await sdk.rbac.assignRoleToUser({
userId: 'user-123',
roleId: 'admin-role-id',
expiresAt: '2024-12-31T23:59:59Z', // Optional expiration
});
console.log(`Assigned role to user: ${userRole.id}`);
Remove Role from User
const removed = await sdk.rbac.removeRoleFromUser('admin-role-id', 'user-123');
console.log(`Role removed: ${removed}`);
Bulk Role Assignment
// Assign multiple roles to a user
const userRoles = await sdk.rbac.bulkAssignRolesToUser(
['role-1', 'role-2', 'role-3'],
'user-123',
'2024-12-31T23:59:59Z' // Optional expiration
);
console.log(`Assigned ${userRoles.length} roles to user`);
// Remove multiple roles from a user
const removed = await sdk.rbac.bulkRemoveRolesFromUser(
['role-1', 'role-2'],
'user-123'
);
console.log(`Bulk removal successful: ${removed}`);
Direct Permission Assignments
Assign Permission to User
For fine-grained control, assign permissions directly to users:
const userPermission = await sdk.rbac.assignPermissionToUser({
userId: 'user-123',
permissionId: 'edit-permission-id',
resourceId: 'project-456',
conditions: { scope: 'own_items_only' }, // Optional conditions
expiresAt: '2024-06-30T23:59:59Z', // Optional expiration
});
console.log(`Direct permission assigned: ${userPermission.id}`);
Assign Permission to Role
const rolePermission = await sdk.rbac.assignPermissionToRole({
roleId: 'manager-role-id',
permissionId: 'delete-permission-id',
resourceId: 'workspace-789',
conditions: { require_approval: true }, // Optional conditions
});
console.log(`Permission assigned to role: ${rolePermission.id}`);
Advanced Usage Patterns
Permission-Based UI Rendering
interface PermissionGuardProps {
permission: string;
resource: string;
children: React.ReactNode;
fallback?: React.ReactNode;
}
const PermissionGuard: React.FC<PermissionGuardProps> = ({
permission,
resource,
children,
fallback = null,
}) => {
const [hasPermission, setHasPermission] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const checkPermission = async () => {
try {
const allowed = await sdk.rbac.checkPermission(permission, resource);
setHasPermission(allowed);
} catch (error) {
console.error('Permission check failed:', error);
setHasPermission(false);
} finally {
setLoading(false);
}
};
checkPermission();
}, [permission, resource]);
if (loading) return <div>Checking permissions...</div>;
return hasPermission ? <>{children}</> : <>{fallback}</>;
};
// Usage
<PermissionGuard permission="delete" resource="project:123">
<DeleteButton projectId="123" />
</PermissionGuard>
Batch Permission Validation
const validateUserAccess = async (userId: string, resources: string[]) => {
const permissionChecks = resources.flatMap(resource => [
{ permission: 'read', resource },
{ permission: 'write', resource },
{ permission: 'delete', resource },
]);
const results = await sdk.rbac.checkMultiplePermissions({
permissions: permissionChecks,
});
// Group results by resource
const accessMap: Record<string, Record<string, boolean>> = {};
results.forEach(result => {
if (!accessMap[result.resource]) {
accessMap[result.resource] = {};
}
accessMap[result.resource][result.permission] = result.hasPermission;
});
return accessMap;
};
// Usage
const userAccess = await validateUserAccess('user-123', [
'project:456',
'workspace:789',
'team:321',
]);
console.log('User access levels:', userAccess);
Role-Based Menu Generation
interface MenuItem {
label: string;
path: string;
permission?: string;
resource?: string;
children?: MenuItem[];
}
const generateUserMenu = async (baseMenu: MenuItem[]): Promise<MenuItem[]> => {
const checkMenuItem = async (item: MenuItem): Promise<MenuItem | null> => {
// If item has permission requirements, check them
if (item.permission && item.resource) {
const hasPermission = await sdk.rbac.checkPermission(
item.permission,
item.resource
);
if (!hasPermission) return null;
}
// Recursively check children
if (item.children) {
const allowedChildren = await Promise.all(
item.children.map(child => checkMenuItem(child))
);
item.children = allowedChildren.filter(child => child !== null) as MenuItem[];
}
return item;
};
const allowedMenuItems = await Promise.all(
baseMenu.map(item => checkMenuItem(item))
);
return allowedMenuItems.filter(item => item !== null) as MenuItem[];
};
// Usage
const baseMenu: MenuItem[] = [
{ label: 'Dashboard', path: '/dashboard' },
{
label: 'Projects',
path: '/projects',
children: [
{ label: 'View Projects', path: '/projects', permission: 'read', resource: 'project:*' },
{ label: 'Create Project', path: '/projects/new', permission: 'create', resource: 'project:*' },
],
},
{ label: 'Admin', path: '/admin', permission: 'admin_access', resource: 'workspace:current' },
];
const userMenu = await generateUserMenu(baseMenu);
Error Handling
try {
const role = await sdk.rbac.createRole({
name: 'Duplicate Role Name',
description: 'This will fail if name exists',
});
} catch (error) {
if (error.message.includes('already exists')) {
console.error('Role name already exists');
} else if (error.message.includes('permission')) {
console.error('Insufficient permissions to create role');
} else {
console.error('Failed to create role:', error.message);
}
}
Best Practices
1. Use Descriptive Permission Names
// Good
await sdk.rbac.checkPermission('edit_project_settings', 'project:123');
await sdk.rbac.checkPermission('view_financial_reports', 'workspace:456');
// Avoid
await sdk.rbac.checkPermission('edit', 'project:123');
await sdk.rbac.checkPermission('view', 'workspace:456');
2. Implement Permission Caching
class PermissionCache {
private cache = new Map<string, { result: boolean; expires: number }>();
private readonly TTL = 5 * 60 * 1000; // 5 minutes
async checkPermission(permission: string, resource: string): Promise<boolean> {
const key = `${permission}:${resource}`;
const cached = this.cache.get(key);
if (cached && Date.now() < cached.expires) {
return cached.result;
}
const result = await sdk.rbac.checkPermission(permission, resource);
this.cache.set(key, {
result,
expires: Date.now() + this.TTL,
});
return result;
}
clearCache(): void {
this.cache.clear();
}
}
const permissionCache = new PermissionCache();
3. Use Resource Hierarchies
// Check permissions at different levels
const canAccessProject = await sdk.rbac.checkPermission('read', 'project:123');
const canAccessWorkspace = await sdk.rbac.checkPermission('read', 'workspace:456');
const canAccessOrg = await sdk.rbac.checkPermission('read', 'organization:789');
// Users with organization access typically have workspace access
// Users with workspace access typically have project access
4. Regular Permission Audits
const auditUserPermissions = async (userId: string) => {
const roles = await sdk.rbac.getRoles();
const userRoles = roles.filter(role =>
// This would need to be implemented based on your user-role relationship queries
// For now, this is pseudocode
role.users?.some(user => user.id === userId)
);
console.log(`User ${userId} has ${userRoles.length} roles:`);
userRoles.forEach(role => {
console.log(`- ${role.name}: ${role.description}`);
});
// Check for redundant permissions
// Check for expired assignments
// Check for excessive privileges
};