Skip to main content

Roles & Permissions API

Heimdall provides full CRUD for roles and permissions via both GraphQL and REST APIs.

GraphQL

Queries

List Roles

query {
roles {
id
name
description
isSystem
requiresTwoFactor
level
createdAt
updatedAt
}
}

Get Role with Permissions

query {
roleWithPermissions(id: "role_admin") {
id
name
description
isSystem
requiresTwoFactor
permissions {
id
resource
action
description
adminOnly
displayOrder
}
}
}

List Permissions

query {
permissions {
id
resource
action
description
adminOnly
displayOrder
createdAt
updatedAt
}
}

Mutations

Create Role

Permission required: roles:write

mutation {
createRole(input: { name: "Editor", description: "Can edit content" }) {
id
name
description
}
}

Update Role

Permission required: roles:write

System roles cannot be updated.

mutation {
updateRole(id: "role_editor", input: { description: "Updated description" }) {
id
name
description
}
}

Delete Role

Permission required: roles:delete

System roles cannot be deleted.

mutation {
deleteRole(id: "role_editor")
}

Assign Permission to Role

Permission required: roles:write

Assigns a permission to a role. Automatically invalidates permission caches and broadcasts updates via WebSocket to affected users.

mutation {
assignRolePermission(roleId: "role_editor", permissionId: "perm_content_write")
}

Remove Permission from Role

Permission required: roles:write

mutation {
removeRolePermission(roleId: "role_editor", permissionId: "perm_content_write")
}

Create Permission

Permission required: permissions:write

mutation {
createPermission(input: {
resource: "content"
action: "write"
description: "Can write content"
adminOnly: false
displayOrder: 10
}) {
id
resource
action
description
}
}

Update Permission

Permission required: permissions:write

mutation {
updatePermission(id: "perm_content_write", input: { description: "Updated" }) {
id
resource
action
description
}
}

Delete Permission

Permission required: permissions:delete

Cannot delete permissions that are still assigned to roles.

mutation {
deletePermission(id: "perm_content_write")
}

User Role Management

Get User Roles

Permission required: users:read

query {
userRoles(userId: "user-123") {
id
name
description
isSystem
requiresTwoFactor
level
createdAt
updatedAt
}
}

Assign Role to User

Permission required: users:write

Assigns a role to a user. Automatically invalidates permission caches and broadcasts roles_updated + permissions_updated via WebSocket.

Role hierarchy enforcement: You can only assign roles with a level strictly below your own highest role level. Super Admins bypass this check. Non-assignable roles (role_system, role_api_full_access, role_api_read_only) are always blocked.

mutation {
assignUserRole(userId: "user-123", roleId: "role_editor")
}

Remove Role from User

Permission required: users:write

Role hierarchy enforcement: You can only remove roles with a level strictly below your own highest role level. Super Admins bypass this check.

mutation {
removeUserRole(userId: "user-123", roleId: "role_editor")
}

REST API

Roles

MethodEndpointPermissionDescription
GET/v1/rolesroles:readList all roles
GET/v1/roles/{id}roles:readGet role by ID
POST/v1/rolesroles:writeCreate role
PATCH/v1/roles/{id}roles:writeUpdate role
DELETE/v1/roles/{id}roles:deleteDelete role
POST/v1/roles/{id}/permissionsroles:writeAssign permission
DELETE/v1/roles/{id}/permissions/{permId}roles:writeRemove permission

Permissions

MethodEndpointPermissionDescription
GET/v1/permissionspermissions:readList all permissions
POST/v1/permissionspermissions:writeCreate permission
PATCH/v1/permissions/{id}permissions:writeUpdate permission
DELETE/v1/permissions/{id}permissions:deleteDelete permission

REST Examples

Create Role

curl -X POST https://api.elcto.com/v1/roles \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Editor", "description": "Can edit content"}'

Assign Permission to Role

curl -X POST https://api.elcto.com/v1/roles/role_editor/permissions \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"permission_id": "perm_content_write"}'

Audit Events

All role and permission mutations are logged as audit events:

EventDescription
role_createdA new role was created
role_updatedA role was updated
role_deletedA role was deleted
role_permission_assignedA permission was assigned to a role
role_permission_removedA permission was removed from a role
permission_createdA new permission was created
permission_updatedA permission was updated
permission_deletedA permission was deleted
role_assignedA role was assigned to a user
role_removedA role was removed from a user

Cache & Real-time Updates

When permissions are assigned/removed from roles:

  1. Redis cache invalidation — Permission caches for all affected users and API keys are cleared
  2. WebSocket broadcastpermissions_updated messages are sent to affected users so frontends can refresh permissions in real-time

Types

Role

interface Role {
id: string;
name: string;
description: string | null;
isSystem: boolean;
requiresTwoFactor: boolean;
/** Hierarchy level (higher = more privileged) */
level: number;
createdAt: string;
updatedAt: string;
}

Default Role Levels

RoleLevel
Super Admin100
Admin80
Moderator60
Developer40
User20
System/API roles0 (non-assignable)

Permission

interface Permission {
id: string;
resource: string;
action: string;
description: string | null;
adminOnly: boolean;
displayOrder: number;
createdAt: string;
updatedAt: string;
}

RoleWithPermissions

interface RoleWithPermissions extends Role {
permissions: Permission[];
}