Skip to main content

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
};