Skip to main content

Roles

Roles are named collections of permissions that can be assigned to users.

Role Model

interface Role {
id: string;
name: string; // Unique within tenant
description: string;
tenantId: string;
scopeLevel: ScopeLevel; // PLATFORM, TENANT, ORGANIZATION
parentId: string | null; // Parent role for inheritance
isSystem: boolean; // System roles cannot be modified
createdAt: Date;
updatedAt: Date;
}

enum ScopeLevel {
PLATFORM = 'PLATFORM',
TENANT = 'TENANT',
ORGANIZATION = 'ORGANIZATION',
}

Create Role

Endpoint

POST /roles

Request

{
"name": "PROJECT_MANAGER",
"description": "Can manage project resources and team members",
"scopeLevel": "ORGANIZATION",
"parentId": "member-role-id"
}

Response (201 Created)

{
"id": "pm-role-id",
"name": "PROJECT_MANAGER",
"description": "Can manage project resources and team members",
"tenantId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"scopeLevel": "ORGANIZATION",
"parentId": "member-role-id",
"isSystem": false,
"createdAt": "2024-01-15T10:30:00.000Z"
}

List Roles

Endpoint

GET /roles

Query Parameters

ParameterTypeDescription
pagenumberPage number
limitnumberItems per page
scopeLevelstringFilter by scope level
searchstringSearch by name

Response (200 OK)

{
"data": [
{
"id": "tenant-admin-id",
"name": "TENANT_ADMIN",
"description": "Full tenant administration",
"scopeLevel": "TENANT",
"isSystem": true
},
{
"id": "org-admin-id",
"name": "ORG_ADMIN",
"description": "Organization administration",
"scopeLevel": "ORGANIZATION",
"isSystem": true
}
],
"pagination": {
"total": 8,
"page": 1,
"limit": 20,
"totalPages": 1
}
}

Get Role

Endpoint

GET /roles/:id

Response (200 OK)

{
"id": "org-admin-id",
"name": "ORG_ADMIN",
"description": "Organization administration",
"scopeLevel": "ORGANIZATION",
"parentId": "member-role-id",
"isSystem": true,
"permissions": [
{
"id": "perm-001",
"resource": "users",
"action": "create"
},
{
"id": "perm-002",
"resource": "users",
"action": "read"
}
]
}

Update Role

Endpoint

PATCH /roles/:id

Request

{
"description": "Updated description"
}
caution

System roles (isSystem: true) cannot be updated.

Delete Role

Endpoint

DELETE /roles/:id

Error: System Role

{
"type": "https://api.cortex.purplelab.ai/errors/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "System roles cannot be deleted"
}

Error: Role In Use

{
"type": "https://api.cortex.purplelab.ai/errors/conflict",
"title": "Conflict",
"status": 409,
"detail": "Cannot delete role: it has active assignments"
}

System Roles

CORTEX includes pre-defined system roles:

RoleScopeDescription
SUPER_ADMINPLATFORMFull system access
TENANT_ADMINTENANTFull tenant access
ORG_ADMINORGANIZATIONFull organization access
MEMBERORGANIZATIONStandard member access
VIEWERORGANIZATIONRead-only access

Code Examples

TypeScript

interface Role {
id: string;
name: string;
description: string;
scopeLevel: 'PLATFORM' | 'TENANT' | 'ORGANIZATION';
parentId: string | null;
isSystem: boolean;
}

interface CreateRoleDto {
name: string;
description: string;
scopeLevel: 'TENANT' | 'ORGANIZATION';
parentId?: string;
}

async function createRole(
accessToken: string,
data: CreateRoleDto
): Promise<Role> {
const response = await fetch('http://localhost:8091/roles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
body: JSON.stringify(data),
});
return response.json();
}

async function listRoles(accessToken: string): Promise<Role[]> {
const response = await fetch('http://localhost:8091/roles', {
headers: { 'Authorization': `Bearer ${accessToken}` },
});
const data = await response.json();
return data.data;
}

cURL

# Create role
curl -X POST http://localhost:8091/roles \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <access-token>" \
-d '{
"name": "PROJECT_MANAGER",
"description": "Manages projects",
"scopeLevel": "ORGANIZATION"
}'

# List roles
curl http://localhost:8091/roles \
-H "Authorization: Bearer <access-token>"

# Get role with permissions
curl http://localhost:8091/roles/org-admin-id \
-H "Authorization: Bearer <access-token>"