# Role-Based Access Control

Control who can do what in your Duro organization with fine-grained, permission-based access control.

## Overview

Duro's RBAC system provides granular control over user access at both the organization and library levels. This allows you to:

* Assign broad organization-wide roles for internal team members
* Grant specific library-level access for external partners or contractors
* Override organization roles for specific libraries when needed
* Create custom roles tailored to your team's workflow

{% hint style="info" %}
RBAC replaces the legacy role enum system with a flexible, permission-based model that supports both system-defined and custom roles.
{% endhint %}

## Core Concepts

### Role Types: A 2x2 Matrix

Duro's RBAC system has two dimensions for understanding roles:

|                 | **Organization Scope**                     | **Library Scope**                        |
| --------------- | ------------------------------------------ | ---------------------------------------- |
| **System Role** | Admin, Editor, Reviewer, Viewer, Supplier  | Admin, Editor, Reviewer, Viewer          |
| **Custom Role** | User-created roles with custom permissions | Automatically created from org templates |

**Scope** determines where the role applies:

* **Organization roles** grant access across all libraries in your organization
* **Library roles** grant access to a specific library only

**Type** determines who manages the role:

* **System roles** are created by Duro and cannot be modified or deleted
* **Custom roles** are created by your organization and fully editable

### Hierarchical Role Resolution

When a user accesses a library, Duro determines their effective permissions using this resolution order:

```
Effective Role = Library Role ?? Organization Role ?? No Access
```

1. **If the user has a library-specific role** → Use that role (takes precedence)
2. **Else if the user has an organization role** → Use that role (applies to all libraries)
3. **Else** → Deny access

This enables powerful access patterns:

| Scenario                        | Org Role | Library Role                | Effective Access                     |
| ------------------------------- | -------- | --------------------------- | ------------------------------------ |
| Internal employee               | Editor   | —                           | Editor access everywhere             |
| Employee with elevated access   | Editor   | Admin (Project X)           | Admin on Project X, Editor elsewhere |
| Employee with restricted access | Admin    | Viewer (Sensitive)          | Viewer on Sensitive, Admin elsewhere |
| External partner                | —        | Supplier (shared libraries) | Supplier on specific libraries only  |

Here's how this looks in practice—a user with an Editor organization role and a Reviewer override for a specific library:

![Edit User Access showing organization role with library override](/files/bfLq8BNQjJgV8k49mS5n)

### Admin Bypass

Roles marked as `isAdmin: true` bypass all permission checks. Admin users automatically have full access without needing individual permissions granted.

## System Roles

System roles are created by Duro and provide baseline access levels for common use cases. They cannot be modified or deleted.

### Organization-Level System Roles

| Role           | Admin? | Best For                              | Description                                                                                                                 |
| -------------- | ------ | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **Site Admin** | Yes    | Organization creators                 | Full system access. Automatically assigned to the user who created the organization.                                        |
| **Admin**      | Yes    | IT administrators, managers           | Organization administrator with full access to all settings and libraries.                                                  |
| **Editor**     | No     | Engineers, designers                  | Standard member who can create and edit components, assemblies, and change orders. Can participate in the full CO workflow. |
| **Reviewer**   | No     | Quality assurance, external reviewers | Can view content and approve/reject/release change orders but cannot create or modify components.                           |
| **Viewer**     | No     | Stakeholders, observers               | Read-only access to view components, assemblies, and change orders.                                                         |
| **Supplier**   | No     | External suppliers, vendors           | Limited read-only access to shared content. Ideal for supply chain partners.                                                |

![Roles & Permissions overview showing system roles with capability breakdowns](/files/trjS6Rd9U6xViHs87poq)

### Library-Level System Roles

Library roles mirror organization roles but apply to a single library:

| Role         | Admin? | Description                                                    |
| ------------ | ------ | -------------------------------------------------------------- |
| **Admin**    | Yes    | Full access to this library including settings and permissions |
| **Editor**   | No     | Can create, edit, and manage content in this library           |
| **Reviewer** | No     | Can view and participate in change order workflow              |
| **Viewer**   | No     | Read-only access to this library                               |

{% hint style="info" %}
Library roles are typically created automatically when you assign a user to a specific library. You don't need to manually create them.
{% endhint %}

## Permission Reference

Permissions follow the naming convention `{resource}.{action}` or `{resource}.{sub-resource}.{action}`.

![Permission categories in the Create Role interface](/files/8C9VfaRZ1ciixSovEVMe)

### Content Management

| Permission                   | UI Label          | Description                                         | Use Case                                                           |
| ---------------------------- | ----------------- | --------------------------------------------------- | ------------------------------------------------------------------ |
| `components.create`          | Create Components | Create new components in the library                | Grant to engineers who design new parts                            |
| `components.read`            | View Components   | View component details, specifications, and history | Required for anyone who needs visibility into the parts database   |
| `components.update`          | Edit Components   | Modify component properties and metadata            | Grant to engineers maintaining part data                           |
| `components.delete`          | Delete Components | Permanently remove components                       | Restrict to administrators; deletion is irreversible               |
| `components.revision.create` | Create Revisions  | Create new revisions of existing components         | Grant to engineers working on part iterations                      |
| `assemblies.create`          | Create Assemblies | Create new assemblies and BOMs                      | Grant to engineers building product structures                     |
| `assemblies.read`            | View Assemblies   | View assembly structures and BOM data               | Required for manufacturing and procurement visibility              |
| `assemblies.update`          | Edit Assemblies   | Modify assembly structure and BOM                   | Grant to engineers maintaining product structures                  |
| `assemblies.delete`          | Delete Assemblies | Permanently remove assemblies                       | Restrict to administrators                                         |
| `library_pins.read`          | View Pins         | View pinned components in a library                 | Grant for quick access to frequently used components               |
| `library_pins.create`        | Pin Components    | Pin components to a library for quick access        | Grant to users who curate commonly-used parts                      |
| `library_pins.delete`        | Unpin Components  | Remove component pins                               | Grant alongside pin creation                                       |
| `labels.create`              | Create Labels     | Create new labels and assign them to components     | Grant to users who organize and categorize components              |
| `labels.read`                | View Labels       | View labels and their assignments                   | Required for anyone who needs to see component categorization      |
| `labels.update`              | Edit Labels       | Modify label names, colors, and descriptions        | Grant to users who maintain label taxonomy                         |
| `labels.delete`              | Delete Labels     | Remove labels from the system                       | Restrict to administrators; affects all components using the label |

### Change Order Workflow

| Permission                       | UI Label          | Description                                  | Use Case                                                  |
| -------------------------------- | ----------------- | -------------------------------------------- | --------------------------------------------------------- |
| `change_orders.create`           | Create COs        | Create new change orders                     | Grant to engineers initiating design changes              |
| `change_orders.read`             | View COs          | View change order details and status         | Required for anyone tracking engineering changes          |
| `change_orders.update`           | Edit COs          | Modify change order details                  | Grant to CO owners and administrators                     |
| `change_orders.delete`           | Delete COs        | Archive or delete change orders              | Restrict to administrators; use sparingly                 |
| `change_orders.submit`           | Submit for Review | Submit a change order for approval           | Grant to engineers who create change orders               |
| `change_orders.approve`          | Approve COs       | Approve change orders in the workflow        | Grant to reviewers, leads, and quality personnel          |
| `change_orders.reject`           | Reject COs        | Reject change orders and return for revision | Grant alongside approve permission                        |
| `change_orders.release`          | Release COs       | Close and release approved change orders     | Grant to release managers or quality leads                |
| `change_orders.withdraw`         | Withdraw COs      | Withdraw a submitted change order            | Grant to CO creators and administrators                   |
| `change_orders.reset`            | Reset COs         | Reset a change order back to draft status    | Restrict to administrators; used for workflow corrections |
| `change_orders.templates.manage` | Manage Templates  | Create and manage change order templates     | Grant to process owners who define CO standards           |

### Collaboration

| Permission          | UI Label          | Description                                     | Use Case                             |
| ------------------- | ----------------- | ----------------------------------------------- | ------------------------------------ |
| `comments.create`   | Add Comments      | Create comments on components and change orders | Grant to enable team discussions     |
| `comments.read`     | View Comments     | View comments and discussions                   | Required for collaborative workflows |
| `comments.update`   | Edit Comments     | Edit your own comments                          | Grant alongside comment creation     |
| `comments.delete`   | Delete Comments   | Delete your own comments                        | Grant alongside comment creation     |
| `comments.moderate` | Moderate Comments | Delete any comment (moderation)                 | Restrict to administrators           |

### Administration

#### Organization Settings

| Permission                       | UI Label            | Description                               | Use Case                                             |
| -------------------------------- | ------------------- | ----------------------------------------- | ---------------------------------------------------- |
| `organization.read`              | View Org Info       | View organization information             | Granted to all members by default                    |
| `organization.settings.update`   | Edit Org Settings   | Update organization settings              | Restrict to administrators                           |
| `organization.users.read`        | View Members        | View organization members                 | Granted to most roles for collaboration              |
| `organization.users.invite`      | Invite Members      | Invite new users to the organization      | Grant to team leads and HR personnel                 |
| `organization.users.remove`      | Remove Members      | Remove users from the organization        | Restrict to administrators                           |
| `organization.users.update_role` | Assign Member Roles | Change user roles within the organization | Restrict to administrators                           |
| `organization.libraries.create`  | Create Libraries    | Create new libraries in the organization  | Grant to administrators and project leads            |
| `organization.libraries.delete`  | Delete Libraries    | Delete libraries from the organization    | Restrict to administrators; deletion is irreversible |
| `organization.saml.configure`    | Configure SSO       | Configure SAML SSO settings               | Restrict to IT administrators                        |
| `organization.api_keys.manage`   | Manage API Keys     | Create and manage API keys                | Grant to developers and integrators                  |

#### Library Settings

| Permission                  | UI Label              | Description                              | Use Case                                          |
| --------------------------- | --------------------- | ---------------------------------------- | ------------------------------------------------- |
| `library.read`              | View Library Info     | View library information                 | Granted to all library members                    |
| `library.settings.update`   | Edit Library Settings | Update library settings                  | Restrict to library administrators                |
| `library.categories.manage` | Manage Categories     | Manage library categories and attributes | Grant to library administrators and data stewards |
| `library.statuses.manage`   | Manage Statuses       | Manage custom component statuses         | Grant to process owners                           |
| `library.features.manage`   | Toggle Features       | Enable/disable experimental features     | Restrict to administrators                        |

#### Role Management

| Permission     | UI Label     | Description                                | Use Case                             |
| -------------- | ------------ | ------------------------------------------ | ------------------------------------ |
| `roles.read`   | View Roles   | View available roles and their permissions | Granted to administrators            |
| `roles.create` | Create Roles | Create custom roles                        | Grant to organization administrators |
| `roles.update` | Edit Roles   | Modify custom role permissions             | Grant to organization administrators |
| `roles.delete` | Delete Roles | Delete custom roles                        | Grant to organization administrators |
| `roles.assign` | Assign Roles | Assign roles to users                      | Grant to user managers               |

## Permission Implications

Some permissions automatically satisfy requirements for related permissions. This follows the principle that higher-level access implies lower-level access.

### How It Works

If a user has a "higher" permission, they automatically satisfy checks for "lower" permissions:

```
delete → update → create → read
```

For example, a user with `components.update` can also perform `components.read` operations, even if `components.read` wasn't explicitly granted.

### Implication Rules

| If user has...                 | They can also...                                                     |
| ------------------------------ | -------------------------------------------------------------------- |
| `components.delete`            | `components.update`, `components.create`, `components.read`          |
| `components.update`            | `components.create`, `components.read`                               |
| `components.create`            | `components.read`                                                    |
| `labels.delete`                | `labels.update`, `labels.create`, `labels.read`                      |
| `labels.update`                | `labels.create`, `labels.read`                                       |
| `labels.create`                | `labels.read`                                                        |
| `change_orders.delete`         | `change_orders.update`, `change_orders.create`, `change_orders.read` |
| Any CO workflow permission     | `change_orders.read`                                                 |
| `comments.moderate`            | All other comment permissions                                        |
| Any role management permission | `roles.read`                                                         |
| Any user management permission | `organization.users.read`                                            |

{% hint style="info" %}
This means you don't need to explicitly grant read permissions if you're granting create, update, or delete permissions on the same resource.
{% endhint %}

## API Reference

### Required Headers

All authenticated GraphQL requests must include context headers:

```
x-organization: @org-slug    # Or organization UUID
x-library: @org-slug/lib     # Or library UUID (for library-scoped operations)
```

### Querying Roles

#### Get All Permissions

Retrieve all available permissions in the system:

```graphql
query GetAllPermissions {
  roles {
    allPermissions {
      id
      name
      description
      resource
      action
    }
  }
}
```

#### Get Role by ID

Retrieve a specific role with its permissions:

```graphql
query GetRole($id: String!) {
  roles {
    findById(id: $id) {
      id
      name
      description
      type
      isAdmin
      isSystemRole
      permissions {
        id
        name
        description
      }
    }
  }
}
```

#### Get Organization Members with Roles

Query organization members to see their assigned roles and library access:

```graphql
query GetOrganizationMembers($slug: String!) {
  organization {
    find(filter: { slug: $slug }) {
      members {
        id
        userId
        user {
          id
          primaryEmail
          name
        }
        rbacRole {
          id
          name
          type
          isAdmin
          permissions {
            name
          }
        }
        hasDirectOrgRole
        libraryAccess {
          libraryId
          libraryName
          role {
            id
            name
          }
          isOverride
        }
      }
    }
  }
}
```

{% hint style="info" %}
The `members` field returns all organization members. To find a specific user, filter the results by `userId` in your application code.
{% endhint %}

### Managing Custom Roles

#### Create a Custom Role

```graphql
mutation CreateRole($input: CreateRoleInput!) {
  roles {
    create(input: $input) {
      id
      name
      description
      type
      isAdmin
      isSystemRole
      permissions {
        id
        name
      }
    }
  }
}
```

**Variables:**

```json
{
  "input": {
    "name": "Quality Engineer",
    "description": "QA team member who reviews and approves changes",
    "type": "ORG",
    "extId": "your-organization-id",
    "permissionIds": [
      "permission-uuid-1",
      "permission-uuid-2"
    ],
    "isAdmin": false
  }
}
```

{% hint style="warning" %}
Creating roles requires the `roles.create` permission.
{% endhint %}

#### Update a Custom Role

```graphql
mutation UpdateRole($input: UpdateRoleInput!) {
  roles {
    update(input: $input) {
      id
      name
      description
      permissions {
        id
        name
      }
    }
  }
}
```

**Variables:**

```json
{
  "input": {
    "id": "role-uuid",
    "organizationId": "org-uuid",
    "name": "Senior Quality Engineer",
    "description": "Updated description",
    "permissionIds": ["updated-permission-list"]
  }
}
```

#### Delete a Custom Role

When deleting a role with assigned users, you must specify a migration target:

```graphql
mutation DeleteRole($input: DeleteRoleInput!) {
  roles {
    delete(input: $input)
  }
}
```

**Variables:**

```json
{
  "input": {
    "id": "role-to-delete-uuid",
    "organizationId": "org-uuid",
    "migrateToRoleId": "target-role-uuid"
  }
}
```

#### Count Users in a Role

Before deleting a role, check how many users are assigned:

```graphql
query CountUsersInRole($roleId: String!) {
  roles {
    usersInRole(roleId: $roleId)
  }
}
```

## Custom Role Best Practices

### When to Create Custom Roles

Create custom roles when system roles don't fit your workflow:

* **QA Engineer**: Read access + change order approval, but no component editing
* **External Auditor**: Read access + export capabilities for compliance reviews
* **Junior Engineer**: Create components but not delete; submit COs but not approve
* **Supply Chain Manager**: Supplier management + procurement-specific permissions

### Custom Role Guidelines

1. **Start from a template** - Use the quick-start templates in the UI to begin with a baseline permission set

![Create Custom Role with quick-start templates](/files/zabNiVJzwSGRTjtfFygd)

2. **Follow least privilege** - Grant only the permissions needed for the role's responsibilities
3. **Document the purpose** - Use the description field to explain who should be assigned this role
4. **Review periodically** - Audit custom roles quarterly to ensure they still align with team needs

### Naming Conventions

* Use job titles or functional descriptions: "Quality Engineer", "External Reviewer"
* Avoid generic names like "Custom Role 1"
* Include scope if relevant: "Library Admin - Prototypes"

## User Access Patterns

![Users & Access list showing different access patterns](/files/JcPSlry5s3MREGIXlMdW)

### Organization-Wide Access

For internal team members who need consistent access across all libraries:

1. Assign an **organization role** (Admin, Editor, Reviewer, Viewer)
2. User automatically gets that role in all libraries, including future ones
3. Optionally add **library overrides** for exceptions

**Example**: An engineer with Editor org role who needs Admin access to their project:

* Org Role: Editor (applies everywhere)
* Library Override: Admin on "Project Phoenix" library

![Invite Team Members with organization role and library access options](/files/fhBVZ7dRfclqFI8lIH6T)

### Per-Library Access

For external partners, contractors, or users with limited scope:

1. **Do not** assign an organization role
2. Add specific **library assignments** with appropriate roles
3. User only has access to explicitly assigned libraries

**Example**: An external supplier:

* No org role
* Supplier role on "Shared Components" library
* Viewer role on "Product Specs" library

## Troubleshooting

### Common Issues

**User can't access a library**

* Check if they have an org role OR a library-specific role
* Verify the library role hasn't been accidentally removed

**User has more access than expected**

* Check for admin bypass (`isAdmin: true` on their role)
* Review permission implications - they may have a higher permission that satisfies the check

**Custom role changes not taking effect**

* Changes to org roles cascade to library roles automatically
* Users may need to refresh their session

### Next Steps

Learn about setting up [Webhooks](/advanced-topics/webhooks.md) to get notified of role and access changes in real-time.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.durohub.com/advanced-topics/rbac.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
