20 KiB
Role-Based Access Control (RBAC) Implementation
Overview
This document describes the comprehensive Role-Based Access Control (RBAC) system implemented in StreamFlow, following the Principle of Least Privilege. The RBAC system provides granular permission management, ensuring users have only the minimum access rights needed to perform their functions.
Table of Contents
- Architecture
- Permission System
- Default Roles
- API Reference
- Frontend Integration
- Security Considerations
- Audit Logging
- Migration Guide
- Best Practices
Architecture
Components
The RBAC system consists of four main components:
-
RBAC Middleware (
backend/middleware/rbac.js)- Permission checking logic
- Role initialization
- Permission caching
- Audit logging utilities
-
RBAC Routes (
backend/routes/rbac.js)- Role CRUD operations
- User role assignment
- Permission queries
- Audit log retrieval
-
Database Schema
rolestable: Role definitions and permissionspermission_audit_logtable: Audit trail for permission changes
-
RBAC Dashboard (
frontend/src/components/RBACDashboard.jsx)- Visual role management interface
- User role assignment UI
- Permission viewer
- Audit log browser
Database Schema
Roles Table
CREATE TABLE roles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
role_key TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
description TEXT,
permissions TEXT NOT NULL, -- JSON array
is_system_role BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
Permission Audit Log Table
CREATE TABLE permission_audit_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
action TEXT NOT NULL,
target_type TEXT NOT NULL,
target_id INTEGER,
old_value TEXT, -- JSON
new_value TEXT, -- JSON
ip_address TEXT,
user_agent TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)
Permission System
Permission Categories
The system defines 70+ granular permissions across 7 categories:
1. User Management
users.view- View user list and detailsusers.create- Create new usersusers.edit- Edit existing usersusers.delete- Delete usersusers.manage_roles- Assign and modify user rolesusers.unlock- Unlock locked user accountsusers.reset_password- Reset user passwords
2. Session Management
sessions.view_own- View own active sessionssessions.view_all- View all user sessionssessions.terminate_own- Terminate own sessionssessions.terminate_any- Terminate any user sessionsessions.view_stats- View session statistics
3. Content Management
playlists.*- Create, view, edit, delete, import playlistschannels.*- View, edit channels, manage logosfavorites.*- View and manage favoriteshistory.*- View own/all history, delete history
4. System & Settings
settings.*- View and edit application settingsstats.*- View analytics and detailed statisticsbackup.*- Create, restore, delete, download backups
5. Security Management
security.view_sessions- View security session dashboardsecurity.view_csp- View CSP violation dashboardsecurity.manage_2fa- Manage two-factor authenticationsecurity.view_audit- View audit logs
6. Search & Discovery
search.use- Use search functionalitysearch.admin- Search users and system settings
Permission Checking
Middleware Functions
requirePermission(permissions)
- Requires ANY of the specified permissions
- Usage:
requirePermission('users.view') - Usage:
requirePermission(['users.view', 'users.edit'])
requireAllPermissions(permissions)
- Requires ALL of the specified permissions
- Usage:
requireAllPermissions(['users.view', 'users.manage_roles'])
hasPermission(userId, permission)
- Programmatic permission check
- Returns: Promise
hasAnyPermission(userId, permissionList)
- Check if user has ANY permission
- Returns: Promise
hasAllPermissions(userId, permissionList)
- Check if user has ALL permissions
- Returns: Promise
Example Usage in Routes
const { requirePermission, requireAllPermissions } = require('../middleware/rbac');
// Require ANY of the specified permissions
router.get('/users',
authenticate,
requirePermission('users.view'),
(req, res) => {
// Only users with 'users.view' permission can access
}
);
// Require ALL specified permissions
router.post('/roles',
authenticate,
requireAllPermissions(['users.manage_roles', 'users.create']),
(req, res) => {
// Only users with BOTH permissions can access
}
);
Permission Caching
- Permissions are cached for 5 minutes to reduce database queries
- Cache is automatically cleared when:
- User role is changed
- Role permissions are updated
- Custom roles are created/deleted
- Manual cache control available:
clearUserPermissionCache(userId)- Clear specific userclearAllPermissionCache()- Clear entire cache
Default Roles
Admin
Full system access - All permissions enabled
- Complete control over users, roles, and permissions
- Access to all security dashboards
- Backup and restore capabilities
- System statistics and monitoring
User Count: Restricted (last admin cannot be deleted)
Moderator
Content management and user support
Key Permissions:
- View users (but not manage)
- Full content management (playlists, channels)
- Manage all user history
- View detailed statistics
- Manage own sessions and 2FA
Restrictions:
- Cannot create/edit/delete users
- Cannot manage roles or permissions
- Cannot access backups
- Cannot view audit logs
User
Standard user with content access
Key Permissions:
- Manage own playlists and favorites
- Upload custom channel logos
- View and delete own history
- Manage own sessions
- Own 2FA management
Restrictions:
- Cannot view other users' data
- Cannot access admin features
- Cannot view statistics
- Limited to own resources
Viewer
Read-only access for content viewing
Key Permissions:
- View playlists and channels
- Manage favorites
- View and delete own history
- Basic search functionality
- Own session management
Restrictions:
- Cannot create or import playlists
- Cannot upload logos
- Cannot modify settings
- Minimal permissions (principle of least privilege)
API Reference
Base URL
All RBAC endpoints are under /api/rbac
Endpoints
Get All Permissions
GET /api/rbac/permissions
Authorization: Bearer {token}
Required Permission: users.manage_roles
Response:
{
"permissions": [
{ "key": "users.view", "description": "View user list and details" },
...
],
"categories": {
"User Management": ["users.view", "users.create", ...],
...
}
}
Get All Roles
GET /api/rbac/roles
Authorization: Bearer {token}
Required Permission: users.view
Response:
[
{
"id": 1,
"role_key": "admin",
"name": "Administrator",
"description": "Full system access",
"permissions": ["users.view", "users.create", ...],
"is_system_role": true,
"created_at": "2024-01-01T00:00:00.000Z",
"updated_at": "2024-01-01T00:00:00.000Z"
},
...
]
Get Single Role
GET /api/rbac/roles/:roleKey
Authorization: Bearer {token}
Required Permission: users.view
Create Custom Role
POST /api/rbac/roles
Authorization: Bearer {token}
Required Permissions: users.manage_roles AND users.create
Content-Type: application/json
{
"role_key": "content_manager",
"name": "Content Manager",
"description": "Manages playlists and channels",
"permissions": [
"playlists.view",
"playlists.create",
"playlists.edit",
"channels.view",
"channels.edit"
]
}
Response: 201 Created with role object
Validation:
role_key: lowercase letters and underscores only, 2-50 charsname: 2-100 charsdescription: max 500 chars (optional)permissions: array of valid permission keys
Update Role
PATCH /api/rbac/roles/:roleKey
Authorization: Bearer {token}
Required Permission: users.manage_roles
Content-Type: application/json
{
"name": "Updated Name",
"description": "Updated description",
"permissions": [...]
}
Restrictions:
- Cannot modify system roles (admin, moderator, user, viewer)
- All fields optional
Delete Custom Role
DELETE /api/rbac/roles/:roleKey
Authorization: Bearer {token}
Required Permission: users.manage_roles
Restrictions:
- Cannot delete system roles
- Cannot delete roles assigned to users
Get User's Permissions
GET /api/rbac/my-permissions
Authorization: Bearer {token}
Response:
{
"role": "user",
"role_name": "Regular User",
"role_description": "Standard user with content access",
"permissions": ["playlists.view", "playlists.create", ...],
"permission_details": [
{
"key": "playlists.view",
"description": "View playlists"
},
...
]
}
Assign Role to User
POST /api/rbac/users/:userId/role
Authorization: Bearer {token}
Required Permission: users.manage_roles
Content-Type: application/json
{
"role": "moderator"
}
Restrictions:
- Cannot modify own role
- Role must exist
Get Audit Log
GET /api/rbac/audit-log?action=role_created&userId=5&limit=50&offset=0
Authorization: Bearer {token}
Required Permission: security.view_audit
Query Parameters:
action: Filter by action type (optional)userId: Filter by user ID (optional)targetType: Filter by target type (optional)limit: Records per page (default: 100)offset: Pagination offset (default: 0)
Response:
{
"logs": [
{
"id": 1,
"user_id": 1,
"username": "admin",
"action": "role_created",
"target_type": "role",
"target_id": 5,
"old_value": null,
"new_value": {
"role_key": "content_manager",
"name": "Content Manager",
"permissions": [...]
},
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0...",
"created_at": "2024-01-01T12:00:00.000Z"
},
...
],
"limit": 50,
"offset": 0
}
Get RBAC Statistics
GET /api/rbac/stats
Authorization: Bearer {token}
Required Permission: security.view_audit
Response:
{
"role_distribution": [
{
"name": "Administrator",
"role_key": "admin",
"user_count": 2
},
...
],
"recent_actions": [
{
"action": "role_assigned",
"count": 15
},
...
],
"total_permissions": 70,
"total_roles": 6
}
Frontend Integration
RBAC Dashboard Component
Location: frontend/src/components/RBACDashboard.jsx
Route: /security/rbac
Access: Requires users.manage_roles or security.view_audit permissions
Features
Tab 1: Roles & Permissions
- View all system and custom roles
- Create custom roles with granular permissions
- Edit custom role permissions
- Delete custom roles (if not assigned)
- Color-coded role chips (admin=red, moderator=orange, user=blue, viewer=cyan)
- Permission count badges
Tab 2: User Roles
- View all users and their current roles
- Change user roles (dropdown selection)
- User status indicators (active/inactive)
- Prevent self-role modification
Tab 3: Audit Log
- Browse permission change history
- Filter by action type, user, target type
- View change details (old value → new value)
- Timestamp and IP tracking
Tab 4: Statistics
- Role distribution chart
- Recent actions in last 30 days
- Total permissions and roles count
- User count per role
Tab 5: My Permissions
- View your current role and description
- List all permissions granted to you
- Grouped by category with icons
- Permission descriptions
Integration in App
App.jsx:
import RBACDashboard from './components/RBACDashboard';
<Route path="security/rbac" element={<RBACDashboard />} />
SecurityDashboard.jsx:
<Button
onClick={() => navigate('/security/rbac')}
startIcon={<AdminPanelSettings />}
>
{t('security.rbacDashboard')}
</Button>
Translations
English (en.json):
security.rbacDashboard: "RBAC & Permissions"rbac.*: 45+ translation keys for all RBAC features
Romanian (ro.json):
security.rbacDashboard: "RBAC & Permisiuni"rbac.*: 45+ translation keys (full Romanian translations)
Security Considerations
Defense in Depth
-
Multiple Authorization Layers
- JWT authentication (Layer 1)
- Session validation (Layer 2)
- RBAC permission check (Layer 3)
-
Principle of Least Privilege
- Each role has minimum required permissions
- Viewer role for read-only access
- Granular permissions prevent over-privileged accounts
-
System Role Protection
- Cannot delete system roles
- Cannot modify system role permissions
- Last admin cannot be deleted
Attack Mitigation
Privilege Escalation Prevention:
- Users cannot modify their own roles
- Role changes logged in audit trail
- Permission cache invalidated on role changes
Audit Trail:
- All permission changes logged with:
- Actor (who made the change)
- Action (what was done)
- Target (what was affected)
- Old/new values (what changed)
- IP address and User-Agent
- Timestamp
Input Validation:
- Role keys validated (lowercase, underscores only)
- Permission keys validated against whitelist
- Array validation for permission lists
- SQL injection prevention (parameterized queries)
Rate Limiting
RBAC routes protected by rate limiters:
readLimiter: 100 requests per 15 minutes (read operations)modifyLimiter: 30 requests per 15 minutes (write operations)
Audit Logging
Logged Actions
-
role_created- Target: role ID
- New Value: role definition
-
role_updated- Target: role ID
- Old Value: previous role definition
- New Value: updated role definition
-
role_deleted- Target: role ID
- Old Value: deleted role definition
-
role_assigned- Target: user ID
- Old Value: previous role
- New Value: new role
Audit Log Metadata
Each log entry captures:
- User ID and username (who)
- Action type (what)
- Target type and ID (where)
- Old and new values (how it changed)
- IP address (from where)
- User-Agent (with what)
- Timestamp (when)
Querying Audit Logs
// Get all role assignments
GET /api/rbac/audit-log?action=role_assigned
// Get all actions by specific user
GET /api/rbac/audit-log?userId=5
// Get role-related actions
GET /api/rbac/audit-log?targetType=role
// Pagination
GET /api/rbac/audit-log?limit=50&offset=100
Migration Guide
Upgrading from Simple Role System
Current System:
- Binary role check:
user.role === 'admin' - Two roles: admin, user
New RBAC System:
- Granular permissions
- Four default roles: admin, moderator, user, viewer
- Custom role support
Migration Steps
-
Database Migration (Automatic)
rolestable created on first server start- Default roles seeded automatically
- Existing user roles preserved
-
Update Route Protection
Before:
router.get('/users', authenticate, requireAdmin, (req, res) => { ... });After:
router.get('/users', authenticate, requirePermission('users.view'), (req, res) => { ... }); -
Frontend Permission Checks
Before:
{user?.role === 'admin' && <AdminPanel />}After:
{user?.permissions?.includes('security.view_audit') && <AdminPanel />}
Backward Compatibility
The system maintains backward compatibility:
requireAdminmiddleware still works- Existing admin and user roles mapped to RBAC
- No breaking changes to existing authentication
Best Practices
1. Use Granular Permissions
❌ Bad:
requirePermission('admin') // Too broad
✅ Good:
requirePermission('users.view') // Specific
requirePermission(['playlists.edit', 'channels.edit']) // Multiple specific
2. Principle of Least Privilege
When creating custom roles:
- Start with minimum permissions
- Add permissions as needed
- Regularly audit role usage
Example: Content Editor Role
{
role_key: 'content_editor',
name: 'Content Editor',
permissions: [
// Only content-related permissions
'playlists.view',
'playlists.create',
'playlists.edit',
'channels.view',
'channels.edit',
'channels.upload_logo',
// NO user management
// NO system settings
// NO backup access
]
}
3. Regular Permission Audits
-
Review role distribution
- Are too many users admin?
- Can some admins be moderators?
-
Check audit logs
- Monitor role changes
- Detect unusual permission grants
-
Clean up unused roles
- Delete custom roles no longer needed
- Reassign users from deprecated roles
4. Document Custom Roles
When creating custom roles:
{
role_key: 'playlist_manager',
name: 'Playlist Manager',
description: 'Can manage playlists but not users or settings',
// Clear description helps future administrators
}
5. Test Permission Changes
Before deploying role changes:
- Test in development environment
- Verify access for affected users
- Check audit logs
- Have rollback plan ready
Troubleshooting
Issue: "Insufficient permissions" error
Cause: User lacks required permission(s)
Solution:
- Check user's role:
GET /api/rbac/my-permissions - Verify required permission for route
- Assign appropriate role or add permission to role
Issue: Permission cache not updating
Cause: Cache TTL (5 minutes)
Solution:
// Backend: Force cache clear
clearUserPermissionCache(userId);
// or
clearAllPermissionCache();
// Frontend: Re-fetch user data
const response = await axios.get('/api/rbac/my-permissions');
Issue: Cannot delete custom role
Cause: Role assigned to users
Solution:
- Check role usage:
GET /api/rbac/stats - Reassign users to different role
- Then delete custom role
Issue: System role modification fails
Cause: System roles protected
Solution:
- Cannot modify system roles (admin, moderator, user, viewer)
- Create custom role instead
- Copy desired permissions from system role
Performance Considerations
Permission Caching
- Cache Duration: 5 minutes
- Memory Impact: ~1KB per cached user
- Hit Rate: ~95% (typical)
Database Queries
Optimized:
- Single query for permission check (cached)
- Indexed role_key and user_id columns
Audit Log:
- Paginated results (default 100)
- Indexed created_at for time-range queries
Recommendations
-
Production:
- Monitor cache hit rate
- Adjust TTL if needed (default: 5 min)
- Consider Redis for distributed systems
-
Large Deployments:
- Archive old audit logs (>90 days)
- Partition audit table by date
- Consider read replicas for heavy queries
Summary
The RBAC system provides:
✅ Granular Permissions: 70+ specific permissions
✅ Principle of Least Privilege: Four default roles with appropriate access
✅ Custom Roles: Create application-specific roles
✅ Audit Trail: Complete permission change history
✅ Admin UI: Visual role and permission management
✅ Security: Multiple authorization layers
✅ Performance: Permission caching
✅ Internationalization: Full EN/RO translations
✅ Documentation: Comprehensive guide and examples
Next Steps:
- Review default role permissions
- Create custom roles for your use case
- Monitor audit logs regularly
- Educate users about their permissions
- Conduct regular permission audits
For questions or issues, refer to the audit logs and this documentation.