Skip to main content

Role Management

Role Management provides a flexible system for organizing user access across your applications and sites. It supports hierarchical application-level roles and site-wide role bundles for comprehensive access control.

Overview

Taruvi Cloud's role management system consists of two complementary role types:

  • App Roles: Hierarchical roles scoped to individual applications with parent-child relationships
  • Site Roles: Flat role bundles that combine multiple App Roles across different applications
  • User Memberships: Assign users to roles with optional expiration dates
graph TD
subgraph "Site Level"
SR1[Site Role: Super Admin]
SR2[Site Role: Content Manager]
end

subgraph "App: CMS"
AR1[App Role: Editor]
AR2[App Role: Publisher]
AR3[App Role: Reviewer]
AR2 --> AR3
end

subgraph "App: Analytics"
AR4[App Role: Analyst]
AR5[App Role: Viewer]
AR4 --> AR5
end

SR1 -.-> AR1
SR1 -.-> AR4
SR2 -.-> AR3
SR2 -.-> AR5

U1[User: Alice] --> SR1
U2[User: Bob] --> AR2
U3[User: Carol] --> SR2

Key Concepts

App Roles

App Roles are hierarchical roles scoped to a specific application. They use a tree structure allowing parent-child relationships for organizing role hierarchies.

Key characteristics:

  • Scoped to a single application
  • Support parent-child hierarchy (e.g., Manager → Editor → Reviewer)
  • Globally unique slug format: {app-slug}-{role-name} (e.g., cms-editor)
  • Role names are immutable after creation
  • Can be included in Site Roles

Site Roles

Site Roles are organization-wide role bundles that combine multiple App Roles from different applications into a single assignable unit. They have no hierarchy.

Key characteristics:

  • Span multiple applications
  • Bundle App Roles for simplified assignment
  • Flat structure (no parent-child relationships)
  • Useful for cross-functional team access

User Role Membership

Users can be assigned to either an App Role or a Site Role (mutually exclusive per membership). Each assignment can optionally have an expiration date.

Key characteristics:

  • Each membership links a user to ONE role (either App Role or Site Role)
  • Optional expiration datetime
  • Tracks who assigned the role (assigned_by)
  • Hard delete (no soft delete)

Response Format

All Role Management API responses use a standardized format:

Success Responses

Single Item Response (GET single, POST, PUT):

{
"status": "success",
"message": "Resource retrieved successfully",
"data": { ... }
}

Paginated List Response (GET list):

{
"status": "success",
"message": "Data retrieved successfully",
"data": [ ... ],
"total": 100
}

Action Response (DELETE, bulk operations):

{
"message": "Operation completed successfully",
"detail": "Additional information"
}

Error Response

{
"error": "Error type",
"detail": "Detailed error message",
"code": "ERROR_CODE"
}

App Roles API

List App Roles

Get all roles for a specific application.

GET /api/app/{app_slug}/roles
Authorization: Bearer YOUR_ACCESS_TOKEN

Query Parameters:

ParameterTypeDescription
searchstringFilter by name (partial match, case-insensitive)
orderingstringSort field (prefix - for descending). Options: name, created_at, updated_at. Default: name
pageintegerPage number (default: 1)
page_sizeintegerItems per page (default: 20, max: 100)

Response:

{
"status": "success",
"message": "Data retrieved successfully",
"data": [
{
"id": 1,
"name": "Manager",
"slug": "cms-manager",
"description": "Full management access",
"is_parent": true,
"app_id": 1,
"app_name": "CMS",
"app_slug": "cms",
"parent_id": null,
"parent_role_slug": null,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
},
{
"id": 2,
"name": "Editor",
"slug": "cms-editor",
"description": "Can edit content",
"is_parent": false,
"app_id": 1,
"app_name": "CMS",
"app_slug": "cms",
"parent_id": 1,
"parent_role_slug": "cms-manager",
"created_at": "2025-01-15T10:05:00Z",
"updated_at": "2025-01-15T10:05:00Z"
}
],
"total": 2
}

Get App Role

GET /api/app/{app_slug}/roles/{role_slug}
Authorization: Bearer YOUR_ACCESS_TOKEN

Response:

{
"status": "success",
"message": "App role retrieved successfully",
"data": {
"id": 1,
"name": "Manager",
"slug": "cms-manager",
"description": "Full management access",
"is_parent": true,
"app_id": 1,
"app_name": "CMS",
"app_slug": "cms",
"parent_id": null,
"parent_role_slug": null,
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z"
}
}

Create App Role

POST /api/app/{app_slug}/roles
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"name": "Editor",
"description": "Can edit and manage content",
"parent_role_slug": "cms-manager"
}

Request Fields:

FieldTypeRequiredDescription
namestringYesRole name (1-100 chars, unique within app)
descriptionstringNoRole description (max 1000 chars)
parent_role_slugstringNoParent role's slug for hierarchy. Omit to create as root role.
Role Name Immutability

Role names cannot be changed after creation. The slug is automatically generated from the app slug and role name in the format {app-slug}-{role-name-slug}. Plan your naming carefully.

Response: 201 Created

{
"status": "success",
"message": "App role created successfully",
"data": {
"id": 3,
"name": "Editor",
"slug": "cms-editor",
"description": "Can edit and manage content",
"is_parent": false,
"app_id": 1,
"app_name": "CMS",
"app_slug": "cms",
"parent_id": 1,
"parent_role_slug": "cms-manager",
"created_at": "2025-01-15T10:10:00Z",
"updated_at": "2025-01-15T10:10:00Z"
}
}

Update App Role

Update a role's description or parent. The name cannot be changed.

PUT /api/app/{app_slug}/roles/{role_slug}
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"description": "Updated description",
"parent_role_slug": "cms-admin"
}

Request Fields:

FieldTypeDescription
descriptionstringUpdated description
parent_role_slugstringNew parent role slug. Use empty string "" to move to root level. Use null or omit to keep unchanged.
note

Attempting to update the name field will return a 400 Bad Request error. To rename a role, delete it and create a new one.

Response: 200 OK

{
"status": "success",
"message": "App role updated successfully",
"data": {
"id": 3,
"name": "Editor",
"slug": "cms-editor",
"description": "Updated description",
"is_parent": false,
"app_id": 1,
"app_name": "CMS",
"app_slug": "cms",
"parent_id": 2,
"parent_role_slug": "cms-admin",
"created_at": "2025-01-15T10:10:00Z",
"updated_at": "2025-01-15T11:00:00Z"
}
}

Delete App Role

DELETE /api/app/{app_slug}/roles/{role_slug}?remove_child_roles=false
Authorization: Bearer YOUR_ACCESS_TOKEN

Query Parameters:

ParameterTypeDefaultDescription
remove_child_rolesbooleanfalseIf true, deletes all descendant roles. If false, child roles are re-parented to the deleted role's parent.

Response: 200 OK

{
"message": "Role deleted successfully",
"detail": "Deleted 1 role(s)"
}

Site Roles API

List Site Roles

GET /api/roles/
Authorization: Bearer YOUR_ACCESS_TOKEN

Query Parameters:

ParameterTypeDescription
searchstringFilter by name
orderingstringSort field (prefix - for descending). Default: name
pageintegerPage number
page_sizeintegerItems per page

Response:

{
"status": "success",
"message": "Data retrieved successfully",
"data": [
{
"id": 1,
"name": "Super Admin",
"slug": "super-admin",
"description": "Full access across all applications",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"app_roles": [
{
"id": 1,
"name": "Manager",
"slug": "cms-manager",
"description": "...",
"is_parent": true,
"app_id": 1,
"app_name": "CMS",
"app_slug": "cms",
"parent_id": null,
"parent_role_slug": null,
"created_at": "...",
"updated_at": "..."
}
]
}
],
"total": 1
}

Get Site Role

GET /api/roles/{slug}
Authorization: Bearer YOUR_ACCESS_TOKEN

Response:

{
"status": "success",
"message": "Site role retrieved successfully",
"data": {
"id": 1,
"name": "Super Admin",
"slug": "super-admin",
"description": "Full access across all applications",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"app_roles": [...]
}
}

Create Site Role

POST /api/roles/
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"name": "Content Team",
"role_slugs": ["cms-editor", "cms-reviewer", "analytics-viewer"]
}

Request Fields:

FieldTypeRequiredDescription
namestringYesSite role name (1-100 chars, globally unique)
role_slugsarrayNoList of App Role slugs to include (use globally unique slugs like cms-editor)

Response: 201 Created

{
"status": "success",
"message": "Site role created successfully",
"data": {
"id": 2,
"name": "Content Team",
"slug": "content-team",
"description": "",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T10:00:00Z",
"app_roles": [...]
}
}

Update Site Role

PUT /api/roles/{slug}
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"name": "Content Team",
"role_slugs": ["cms-editor", "cms-publisher", "analytics-viewer"]
}

Response: 200 OK

{
"status": "success",
"message": "Site role updated successfully",
"data": {
"id": 2,
"name": "Content Team",
"slug": "content-team",
"description": "",
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-01-15T11:00:00Z",
"app_roles": [...]
}
}

Delete Site Role

DELETE /api/roles/{slug}
Authorization: Bearer YOUR_ACCESS_TOKEN

Response: 200 OK

{
"message": "Site role deleted successfully"
}
warning

Deleting a Site Role will remove all user memberships associated with it.

User Role Membership API

The membership API provides role-centric, user-centric, and bulk operations.

Bulk Operations

Efficiently assign or revoke multiple roles to/from multiple users in a single request. These APIs are designed for batch operations and return detailed failure information for any operations that couldn't be completed.

Bulk Assign Roles

Assign multiple roles to multiple users in a single request. Existing assignments are silently skipped.

POST /api/assign/roles
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"roles": ["cms-editor", "analytics-viewer", "content-team"],
"usernames": ["alice.johnson", "bob.smith", "carol.williams"],
"expires_at": "2025-12-31T23:59:59Z"
}

Request Fields:

FieldTypeRequiredDescription
rolesarrayYesList of role slugs (can mix App Roles and Site Roles). Min: 1, Max: 100
usernamesarrayYesList of usernames to assign roles to. Min: 1, Max: 100
expires_atdatetimeNoOptional expiration for all assignments (applies to all role-user pairs)
Mixed Role Types

You can mix App Role slugs (e.g., cms-editor) and Site Role slugs (e.g., content-team) in the same request. The system automatically determines the role type based on the slug.

Response (Success - All operations completed): 200 OK

{
"message": "Assigned 9 roles successfully"
}

Response (Partial Success - Some operations failed): 200 OK

{
"status": "success",
"message": "Assigned 7 roles, 2 failed",
"data": {
"failures": [
{
"username": "invalid_user",
"role": "cms-editor",
"error": "User not found"
},
{
"username": "alice.johnson",
"role": "nonexistent-role",
"error": "Role not found"
}
]
}
}
Idempotent Operation

Users who already have a role are silently skipped and counted as successful. This allows idempotent operations without errors.

Bulk Revoke Roles

Revoke multiple roles from multiple users in a single request. Non-existing assignments are silently skipped.

DELETE /api/revoke/roles
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"roles": ["cms-editor", "analytics-viewer"],
"usernames": ["alice.johnson", "bob.smith"]
}

Request Fields:

FieldTypeRequiredDescription
rolesarrayYesList of role slugs to revoke (can mix App Roles and Site Roles). Min: 1, Max: 100
usernamesarrayYesList of usernames to revoke roles from. Min: 1, Max: 100

Response (Success - All operations completed): 200 OK

{
"message": "Revoked 4 roles successfully"
}

Response (Partial Success - Some operations failed): 200 OK

{
"status": "success",
"message": "Revoked 2 roles, 2 failed",
"data": {
"failures": [
{
"username": "invalid_user",
"role": "cms-editor",
"error": "User not found"
},
{
"username": "alice.johnson",
"role": "nonexistent-role",
"error": "Role not found"
}
]
}
}
Idempotent Operation

Users who don't have a role are silently skipped and counted as successful. This allows idempotent operations without errors.

Role-Centric Operations

Operate on users assigned to a specific role. Works with both App Role and Site Role slugs.

List Users in Role

GET /api/roles/{role_slug}/users
Authorization: Bearer YOUR_ACCESS_TOKEN

Query Parameters:

ParameterTypeDescription
searchstringFilter by username or email
usernamestringFilter by exact username
include_expiredbooleanInclude expired memberships (default: false)
orderingstringSort field. Options: username, email, first_name, last_name. Default: -created_at

Response:

{
"status": "success",
"message": "Data retrieved successfully",
"data": [
{
"username": "alice.johnson",
"email": "[email protected]",
"first_name": "Alice",
"last_name": "Johnson"
},
{
"username": "bob.smith",
"email": "[email protected]",
"first_name": "Bob",
"last_name": "Smith"
}
],
"total": 2
}

Add Users to Role

POST /api/roles/{role_slug}/users
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"usernames": ["alice.johnson", "bob.smith", "carol.williams"]
}
Idempotent Operation

Users already assigned to the role are silently skipped. This allows idempotent operations without errors.

Response: 200 OK

{
"message": "Users assigned to role successfully",
"detail": "Assigned 3 user(s), skipped 0 existing"
}

Replace All Users in Role

Remove all existing users and assign only the specified users.

PUT /api/roles/{role_slug}/users
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"usernames": ["alice.johnson", "david.brown"]
}

Response: 200 OK

{
"message": "Users replaced successfully",
"detail": "Assigned 2 user(s) to role"
}

Update User Expiration

Update expiration dates for users in a role.

PATCH /api/roles/{role_slug}/users
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"usernames": ["alice.johnson", "bob.smith"],
"expires_at": "2025-12-31T23:59:59Z"
}

Set expires_at to null for permanent access (no expiration).

Expiration Validation

The expiration date must be in the future. Past dates will return a validation error.

Response: 200 OK

{
"message": "Membership updated successfully",
"detail": "Updated 2 user(s)"
}

Remove Users from Role (Bulk)

Remove one or more users from a role. Users not assigned to the role are silently skipped.

DELETE /api/roles/{role_slug}/users
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"usernames": ["alice.johnson", "bob.smith"]
}

Request Fields:

FieldTypeRequiredDescription
usernamesarrayYesList of usernames to remove from the role (min: 1)

Response: 200 OK

{
"message": "Users removed from role successfully",
"detail": "Removed 2 user(s), 0 not assigned"
}

User-Centric Operations

Operate on roles for a specific user.

Get All User's Roles

Get all roles (both App Roles and Site Roles) assigned to a user. Supports filtering by app, membership type, and search.

GET /api/users/{username}/roles
Authorization: Bearer YOUR_ACCESS_TOKEN

Use me as the username to get the current authenticated user's roles:

GET /api/users/me/roles
Authorization: Bearer YOUR_ACCESS_TOKEN

Query Parameters:

ParameterTypeDescription
appstringFilter app roles by app slug (e.g., ?app=cms to get only CMS app roles)
searchstringFilter by role name (partial match, case-insensitive)
membership_typestringFilter by type: app_role or site_role
include_expiredbooleanInclude expired memberships (default: false)
orderingstringSort field (default: -created_at)

Example: Get roles for a specific app:

GET /api/users/alice/roles?app=cms
Authorization: Bearer YOUR_ACCESS_TOKEN

Example: Get only site roles:

GET /api/users/alice/roles?membership_type=site_role
Authorization: Bearer YOUR_ACCESS_TOKEN

Response:

{
"status": "success",
"message": "User roles retrieved successfully",
"data": {
"app_roles": [
{
"name": "Editor",
"slug": "cms-editor"
},
{
"name": "Viewer",
"slug": "analytics-viewer"
}
],
"site_roles": [
{
"name": "Content Team",
"slug": "content-team"
}
]
}
}
App Filter

Use the app query parameter to filter roles for a specific application. This replaces the previous /api/users/{username}/app/{app_slug}/roles endpoint with a more flexible filtering approach.

Assign Roles to User

Assign multiple roles to a user in a single request. You can mix App Role and Site Role slugs.

POST /api/users/{username}/roles
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"role_slugs": ["cms-editor", "analytics-viewer", "content-team"],
"expires_at": "2025-06-30T23:59:59Z"
}

Request Fields:

FieldTypeRequiredDescription
role_slugsarrayYesList of App Role or Site Role slugs
expires_atdatetimeNoOptional expiration for all assignments (null for permanent)
Mixed Role Types

You can mix App Role slugs (e.g., cms-editor) and Site Role slugs (e.g., content-team) in the same request. The system automatically determines the role type based on the slug.

Response: 200 OK

{
"message": "Roles assigned to user successfully",
"detail": "Assigned 3 role(s), skipped 0 existing"
}

Remove Roles from User

Remove one or more roles from a user. Use me as the username to operate on the current authenticated user. Roles not assigned to the user are silently skipped.

DELETE /api/users/{username}/roles
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
"role_slugs": ["cms-editor", "analytics-viewer"]
}

Request Fields:

FieldTypeRequiredDescription
role_slugsarrayYesList of App Role or Site Role slugs to remove (min: 1)

Response: 200 OK

{
"message": "Roles removed from user successfully",
"detail": "Removed 2 role(s), 0 not assigned"
}
Mixed Role Types

You can mix App Role slugs (e.g., cms-editor) and Site Role slugs (e.g., content-team) in the same request. The system automatically determines the role type based on the slug.

Role Hierarchy Operations

Query the hierarchy of App Roles. These endpoints only work with App Roles.

Get Descendant Roles

Get all roles below a role in the hierarchy (children, grandchildren, etc.).

GET /api/roles/{role_slug}/descendants
Authorization: Bearer YOUR_ACCESS_TOKEN

Response:

{
"status": "success",
"message": "Data retrieved successfully",
"data": [
{
"name": "Editor",
"slug": "cms-editor"
},
{
"name": "Reviewer",
"slug": "cms-reviewer"
},
{
"name": "Junior Reviewer",
"slug": "cms-junior-reviewer"
}
],
"total": 3
}

Get Ancestor Roles

Get all roles above a role in the hierarchy (parents, grandparents, etc.).

GET /api/roles/{role_slug}/ancestors
Authorization: Bearer YOUR_ACCESS_TOKEN

Response:

{
"status": "success",
"message": "Data retrieved successfully",
"data": [
{
"name": "Manager",
"slug": "cms-manager"
}
],
"total": 1
}
Hierarchy Limitations

Hierarchy queries (/descendants and /ancestors) only work with App Roles. Using a Site Role slug will return a 400 Bad Request error because Site Roles have no hierarchy.

Response Codes

CodeDescription
200 OKRequest successful
201 CreatedResource created successfully
400 Bad RequestInvalid request (validation error, name change attempt, hierarchy query on Site Role)
401 UnauthorizedAuthentication required
403 ForbiddenInsufficient permissions
404 Not FoundResource not found (role, user, or membership)
409 ConflictDuplicate role (role with same name already exists in app)

Best Practices

Role Design

  1. Plan Hierarchy Carefully: Role names are immutable. Design your role structure before creating roles.

  2. Use Meaningful Names: Choose descriptive names that indicate the role's purpose (e.g., "Content Editor" instead of "Role1").

  3. Leverage Site Roles: Create Site Roles for common permission bundles to simplify user management across applications.

  4. Keep Hierarchies Shallow: Deep hierarchies (more than 3-4 levels) can become difficult to manage.

User Management

  1. Use Expiration Dates: For temporary access (contractors, trials, project-based access), always set expiration dates.

  2. Use Bulk Operations: Use the POST endpoint to add multiple users at once rather than individual calls.

  3. Regular Audits: Periodically review role memberships, especially those with no expiration.

  4. Use "me" Keyword: For user self-service operations, use me as the username to operate on the current user.

Security

  1. Least Privilege: Assign users the minimum roles needed for their tasks.

  2. Site Roles for Cross-App Access: Use Site Roles when users need access across multiple applications rather than assigning multiple individual App Roles.

  3. Monitor Expired Memberships: Use include_expired=true to audit expired memberships and clean up stale assignments.

Common Use Cases

Onboarding a New Team Member

# Assign multiple roles with expiration (e.g., probation period)
POST /api/users/new.employee/roles
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"role_slugs": ["cms-editor", "analytics-viewer"],
"expires_at": "2025-03-31T23:59:59Z"
}

Creating a Department Role Bundle

# Create Site Role bundling multiple App Roles
POST /api/roles/
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"name": "Marketing Team",
"role_slugs": [
"cms-editor",
"cms-publisher",
"analytics-viewer",
"social-manager"
]
}

Setting Up Role Hierarchy

# Create parent role
POST /api/app/cms/roles
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"name": "Manager",
"description": "Full content management access"
}

# Create child role under Manager
POST /api/app/cms/roles
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"name": "Editor",
"description": "Can edit and publish content",
"parent_role_slug": "cms-manager"
}

# Create grandchild role under Editor
POST /api/app/cms/roles
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"name": "Reviewer",
"description": "Can review content only",
"parent_role_slug": "cms-editor"
}

Temporary Project Access

# Add users to a project role
POST /api/roles/project-alpha-team/users
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"usernames": ["contractor1", "contractor2"]
}

# Set expiration for the project
PATCH /api/roles/project-alpha-team/users
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"usernames": ["contractor1", "contractor2"],
"expires_at": "2025-06-30T23:59:59Z"
}

Bulk Onboarding Multiple Team Members

# Assign multiple roles to multiple new hires in one request
POST /api/assign/roles
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"roles": ["cms-editor", "analytics-viewer", "team-member"],
"usernames": ["new.hire1", "new.hire2", "new.hire3", "new.hire4"],
"expires_at": "2025-06-30T23:59:59Z"
}

Bulk Offboarding

# Remove all project roles from departing team members
DELETE /api/revoke/roles
Content-Type: application/json
Authorization: Bearer YOUR_ACCESS_TOKEN

{
"roles": ["project-alpha-dev", "project-alpha-reviewer", "team-member"],
"usernames": ["departing.user1", "departing.user2"]
}

Checking Current User's Access

# Get your own roles
GET /api/users/me/roles
Authorization: Bearer YOUR_ACCESS_TOKEN

# Get your roles for a specific app
GET /api/users/me/app/cms/roles
Authorization: Bearer YOUR_ACCESS_TOKEN

Querying Role Hierarchy

# Get all roles under "Manager"
GET /api/roles/cms-manager/descendants
Authorization: Bearer YOUR_ACCESS_TOKEN

# Get all roles above "Reviewer"
GET /api/roles/cms-reviewer/ancestors
Authorization: Bearer YOUR_ACCESS_TOKEN