15 KiB
Roles & Permissions API
Endpoints for managing role-based access control (RBAC) including roles and permissions.
List Roles
Get all roles with their permissions.
Endpoint: GET /api/roles
Authentication: Required
Permissions: roles.read
Response: 200 OK
[
{
"id": 1,
"name": "admin",
"description": "System administrator with full access",
"priority": 100,
"isSystem": true,
"createdAt": "2024-01-01T00:00:00Z",
"permissions": [
{
"id": 1,
"name": "games.play",
"description": "Play games in browser",
"category": "games"
},
{
"id": 2,
"name": "games.read",
"description": "View game details",
"category": "games"
},
{
"id": 10,
"name": "users.create",
"description": "Create new users",
"category": "users"
}
]
},
{
"id": 2,
"name": "user",
"description": "Standard user with basic permissions",
"priority": 10,
"isSystem": true,
"createdAt": "2024-01-01T00:00:00Z",
"permissions": [
{
"id": 1,
"name": "games.play",
"description": "Play games in browser",
"category": "games"
},
{
"id": 2,
"name": "games.read",
"description": "View game details",
"category": "games"
},
{
"id": 5,
"name": "playlists.create",
"description": "Create playlists",
"category": "playlists"
}
]
}
]
Examples:
curl http://localhost:3100/api/roles \
-H "Authorization: Bearer <token>"
const { data: roles } = await axios.get(
'http://localhost:3100/api/roles',
{ headers: { Authorization: `Bearer ${token}` } }
);
// Use in role selector
const roleOptions = roles.map(role => ({
label: `${role.name} - ${role.description}`,
value: role.id
}));
List Permissions
Get all available permissions in the system.
Endpoint: GET /api/roles/permissions
Authentication: Required
Permissions: roles.read
Response: 200 OK
[
{
"id": 1,
"name": "games.play",
"description": "Play games in browser",
"category": "games"
},
{
"id": 2,
"name": "games.read",
"description": "View game details",
"category": "games"
},
{
"id": 3,
"name": "games.download",
"description": "Download game files",
"category": "games"
},
{
"id": 5,
"name": "playlists.create",
"description": "Create playlists",
"category": "playlists"
},
{
"id": 6,
"name": "playlists.update",
"description": "Update own playlists",
"category": "playlists"
},
{
"id": 7,
"name": "playlists.delete",
"description": "Delete own playlists",
"category": "playlists"
},
{
"id": 10,
"name": "users.read",
"description": "View user list",
"category": "users"
},
{
"id": 11,
"name": "users.create",
"description": "Create new users",
"category": "users"
},
{
"id": 12,
"name": "users.update",
"description": "Update user information",
"category": "users"
},
{
"id": 13,
"name": "users.delete",
"description": "Delete users",
"category": "users"
},
{
"id": 20,
"name": "roles.read",
"description": "View roles and permissions",
"category": "roles"
},
{
"id": 21,
"name": "roles.create",
"description": "Create new roles",
"category": "roles"
},
{
"id": 22,
"name": "roles.update",
"description": "Update roles",
"category": "roles"
},
{
"id": 23,
"name": "roles.delete",
"description": "Delete roles",
"category": "roles"
}
]
Examples:
curl http://localhost:3100/api/roles/permissions \
-H "Authorization: Bearer <token>"
const { data: permissions } = await axios.get(
'http://localhost:3100/api/roles/permissions',
{ headers: { Authorization: `Bearer ${token}` } }
);
// Group by category
const grouped = permissions.reduce((acc, perm) => {
if (!acc[perm.category]) acc[perm.category] = [];
acc[perm.category].push(perm);
return acc;
}, {});
Get Role
Get detailed information about a specific role.
Endpoint: GET /api/roles/:id
Authentication: Required
Permissions: roles.read
URL Parameters:
id(integer, required) - Role ID
Response: 200 OK
{
"id": 2,
"name": "user",
"description": "Standard user with basic permissions",
"priority": 10,
"isSystem": true,
"createdAt": "2024-01-01T00:00:00Z",
"permissions": [
{
"id": 1,
"name": "games.play",
"description": "Play games in browser",
"category": "games"
},
{
"id": 2,
"name": "games.read",
"description": "View game details",
"category": "games"
},
{
"id": 5,
"name": "playlists.create",
"description": "Create playlists",
"category": "playlists"
},
{
"id": 6,
"name": "playlists.update",
"description": "Update own playlists",
"category": "playlists"
},
{
"id": 7,
"name": "playlists.delete",
"description": "Delete own playlists",
"category": "playlists"
}
]
}
Error Responses:
404 Not Found- Role not found
Examples:
curl http://localhost:3100/api/roles/2 \
-H "Authorization: Bearer <token>"
const roleId = 2;
const { data: role } = await axios.get(
`http://localhost:3100/api/roles/${roleId}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
Create Role
Create a new custom role with permissions.
Endpoint: POST /api/roles
Authentication: Required
Permissions: roles.create
Request Body:
{
"name": "string (min: 3, max: 50)",
"description": "string (optional)",
"priority": "integer (default: 0)",
"permissionIds": "array of integers (optional)"
}
Response: 201 Created
{
"id": 5,
"name": "moderator",
"description": "Moderator with limited admin permissions",
"priority": 50,
"isSystem": false,
"createdAt": "2024-03-21T10:00:00Z",
"permissions": [
{
"id": 1,
"name": "games.play",
"description": "Play games in browser",
"category": "games"
},
{
"id": 2,
"name": "games.read",
"description": "View game details",
"category": "games"
},
{
"id": 10,
"name": "users.read",
"description": "View user list",
"category": "users"
}
]
}
Error Responses:
400 Bad Request- Validation error409 Conflict- Role name already exists
Examples:
curl -X POST http://localhost:3100/api/roles \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "moderator",
"description": "Moderator with limited admin permissions",
"priority": 50,
"permissionIds": [1, 2, 10]
}'
const newRole = await axios.post(
'http://localhost:3100/api/roles',
{
name: 'moderator',
description: 'Moderator with limited admin permissions',
priority: 50,
permissionIds: [1, 2, 10, 11]
},
{ headers: { Authorization: `Bearer ${token}` } }
);
Update Role
Update role metadata (name, description, priority). Use separate endpoint to update permissions.
Endpoint: PATCH /api/roles/:id
Authentication: Required
Permissions: roles.update
URL Parameters:
id(integer, required) - Role ID
Request Body:
All fields are optional:
{
"name": "string (min: 3, max: 50, optional)",
"description": "string (optional)",
"priority": "integer (optional)"
}
Response: 200 OK
{
"id": 5,
"name": "senior_moderator",
"description": "Senior moderator with extended permissions",
"priority": 75,
"isSystem": false,
"createdAt": "2024-03-21T10:00:00Z",
"permissions": [...]
}
Error Responses:
400 Bad Request- Validation error or cannot modify system role404 Not Found- Role not found409 Conflict- Role name already exists
Examples:
curl -X PATCH http://localhost:3100/api/roles/5 \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "senior_moderator",
"priority": 75
}'
const roleId = 5;
const { data: updatedRole } = await axios.patch(
`http://localhost:3100/api/roles/${roleId}`,
{
name: 'senior_moderator',
description: 'Senior moderator with extended permissions',
priority: 75
},
{ headers: { Authorization: `Bearer ${token}` } }
);
Update Role Permissions
Replace all permissions for a role.
Endpoint: PUT /api/roles/:id/permissions
Authentication: Required
Permissions: roles.update
URL Parameters:
id(integer, required) - Role ID
Request Body:
{
"permissionIds": [1, 2, 5, 6, 7, 10, 11]
}
Response: 200 OK
{
"id": 5,
"name": "moderator",
"description": "Moderator with limited admin permissions",
"priority": 50,
"isSystem": false,
"createdAt": "2024-03-21T10:00:00Z",
"permissions": [
{
"id": 1,
"name": "games.play",
"description": "Play games in browser",
"category": "games"
},
{
"id": 2,
"name": "games.read",
"description": "View game details",
"category": "games"
},
{
"id": 10,
"name": "users.read",
"description": "View user list",
"category": "users"
},
{
"id": 11,
"name": "users.create",
"description": "Create new users",
"category": "users"
}
]
}
Error Responses:
400 Bad Request- Validation error or cannot modify system role404 Not Found- Role not found
Examples:
curl -X PUT http://localhost:3100/api/roles/5/permissions \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"permissionIds": [1, 2, 5, 6, 7, 10, 11]
}'
const roleId = 5;
const permissionIds = [1, 2, 5, 6, 7, 10, 11];
const { data: updatedRole } = await axios.put(
`http://localhost:3100/api/roles/${roleId}/permissions`,
{ permissionIds },
{ headers: { Authorization: `Bearer ${token}` } }
);
Delete Role
Delete a custom role. Cannot delete system roles (admin, user, moderator, guest).
Endpoint: DELETE /api/roles/:id
Authentication: Required
Permissions: roles.delete
URL Parameters:
id(integer, required) - Role ID
Response: 200 OK
{
"success": true,
"message": "Role deleted successfully"
}
Error Responses:
400 Bad Request- Cannot delete system role404 Not Found- Role not found
Examples:
curl -X DELETE http://localhost:3100/api/roles/5 \
-H "Authorization: Bearer <token>"
const roleId = 5;
await axios.delete(
`http://localhost:3100/api/roles/${roleId}`,
{ headers: { Authorization: `Bearer ${token}` } }
);
System Roles
The following roles are built-in and cannot be deleted or have their core permissions modified:
Admin (ID: 1)
Priority: 100
Description: System administrator with full access to all features.
Key Permissions:
- All game permissions
- All playlist permissions
- All user management permissions
- All role management permissions
- System configuration access
User (ID: 2)
Priority: 10
Description: Standard user with basic access.
Key Permissions:
games.play- Play gamesgames.read- View game detailsplaylists.create- Create playlistsplaylists.update- Update own playlistsplaylists.delete- Delete own playlists
Moderator (ID: 3)
Priority: 50
Description: Moderator with limited admin capabilities.
Key Permissions:
- All user permissions
users.read- View user list- Limited content moderation capabilities
Guest (ID: 4)
Priority: 1
Description: Guest user with read-only access.
Key Permissions:
games.read- View game details- No play or modification permissions
Permission Categories
Permissions are organized into categories:
Games (games)
games.play- Play games in browsergames.read- View game detailsgames.download- Download game filesgames.manage- Manage game metadata (future)
Playlists (playlists)
playlists.create- Create new playlistsplaylists.update- Update own playlistsplaylists.delete- Delete own playlistsplaylists.manage- Manage all playlists (admin)
Users (users)
users.read- View user listusers.create- Create new usersusers.update- Update user informationusers.delete- Delete users
Roles (roles)
roles.read- View roles and permissionsroles.create- Create new rolesroles.update- Update rolesroles.delete- Delete roles
System (system)
system.settings- Manage system settingssystem.maintenance- Perform maintenance taskssystem.logs- View system logs
RBAC Best Practices
Role Design
- Principle of Least Privilege: Grant only necessary permissions
- Separation of Duties: Create distinct roles for different responsibilities
- Role Hierarchy: Use priority field to establish role hierarchy
- System Roles: Never delete or drastically modify system roles
Permission Management
- Granular Permissions: Use specific permissions (e.g.,
users.createvs broadusers.manage) - Category Organization: Keep permissions organized by category
- Documentation: Maintain clear permission descriptions
- Regular Audits: Periodically review role permissions
Implementation
// Check if user has specific permission
function hasPermission(user, permission) {
return user.permissions.includes(permission);
}
// Frontend route protection
if (!hasPermission(user, 'users.read')) {
// Redirect or show error
}
// Backend middleware (automatic via requirePermission)
router.get('/users',
authenticate,
requirePermission('users.read'),
getUsersHandler
);
Custom Role Example
Creating a "Content Manager" role:
// 1. Get available permissions
const { data: permissions } = await axios.get('/api/roles/permissions');
// 2. Select relevant permissions
const contentManagerPerms = permissions
.filter(p =>
p.category === 'games' ||
(p.category === 'playlists' && p.name !== 'playlists.delete')
)
.map(p => p.id);
// 3. Create role
await axios.post('/api/roles', {
name: 'content_manager',
description: 'Manages game content and playlists',
priority: 40,
permissionIds: contentManagerPerms
});
Migration Guide
When adding new permissions:
- Add permission to database via migration
- Update permission list in RoleService
- Assign to relevant system roles
- Document permission in API docs
- Update frontend permission checks