> For the complete documentation index, see [llms.txt](https://docs.durohub.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.durohub.com/advanced-topics/scim-provisioning.md).

# SCIM Provisioning

Automatically provision and deprovision users and teams in your Duro organization from your identity provider (IdP) using SCIM 2.0, keeping Duro in lock-step with the source of truth for your workforce.

{% hint style="info" %}
SCIM provisioning is an enterprise capability that works alongside [SAML SSO](/advanced-topics/saml-sso-setup.md). SAML answers *"who is this person and may they log in?"* SCIM answers *"which users and teams exist, and who belongs to them?"*
{% endhint %}

## Overview

SCIM (System for Cross-domain Identity Management) 2.0 lets your IdP — Okta, Microsoft Entra ID, JumpCloud, OneLogin, and others — push user and group changes to Duro automatically. When someone joins a group in your IdP, they appear on the corresponding Duro team. When they leave the company, their Duro access is revoked without a manual step.

Duro exposes a standard SCIM 2.0 endpoint at a dedicated per-tenant SCIM host — `https://scim-<tenant>.durohub.com/scim/v2` — which is separate from the API host you use for GraphQL. Your IdP authenticates to it with a bearer token that is pinned to a single organization.

### Two independent rails

SCIM and SAML SSO are separate integrations that happen to share an IdP. Keep them straight:

* **SAML SSO** handles authentication. It runs IdP → Auth0 → Duro. See [SAML SSO Setup](/advanced-topics/saml-sso-setup.md).
* **SCIM** handles provisioning. Your IdP calls Duro's `/scim/v2` endpoint directly, authenticated by a bearer token. Auth0 is **not** in the SCIM path.

### What SCIM manages (and what it doesn't)

| SCIM provisions                    | Duro manages                                           |
| ---------------------------------- | ------------------------------------------------------ |
| Users (create, update, deactivate) | Roles on teams (organization role + library overrides) |
| Groups → Teams                     | Which teams get which access                           |
| Group membership → Team membership | —                                                      |

{% hint style="warning" %}
**Roles are always assigned in Duro, never by the IdP.** SCIM provisions team *membership* only. Duro intentionally does not consume the SCIM `roles` attribute. After a team is provisioned, a Duro administrator assigns its organization role and any per-library overrides. See [Role-Based Access Control](/advanced-topics/rbac.md#team-based-access-control) for how team roles resolve into effective access.
{% endhint %}

## Prerequisites

Before enabling SCIM, ensure you have:

* **SAML SSO already enabled for the organization.** SCIM builds on the SAML identity foundation — enabling SCIM without SAML is rejected. Complete [SAML SSO Setup](/advanced-topics/saml-sso-setup.md) first.
* **Duro organization admin access** (Site Admin role) with permission to manage authentication settings.
* **Administrative access to your IdP** to configure a SCIM provisioning app.

{% hint style="info" %}
Because SCIM depends on SAML, **disabling SAML automatically disables SCIM** as well. The two are linked as a symmetric cascade — you cannot have SCIM active without SAML active.
{% endhint %}

## Quick Start

1. **Enable SAML SSO** for the organization (see [SAML SSO Setup](/advanced-topics/saml-sso-setup.md)).
2. **Enable SCIM Provisioning** in Org Settings → Authentication.
3. **Mint a bearer token** — copy it immediately, it is shown only once.
4. **Point your IdP** at the SCIM base URL and paste in the bearer token.
5. **Map IdP groups to Duro teams** by assigning groups to the provisioning app.
6. **Assign each team's role** (organization role + library overrides) in Duro.

The sections below walk through each phase.

### Phase 1: Enable SCIM in Duro

**Duration**: 2 minutes

1. Sign in to Duro with an account that has the **Site Admin** role.
2. Navigate to your organization's authentication settings:
   * Format: `https://{your-duro-domain}/org/@{company-org-slug}/settings/authentication`
3. Confirm **SAML SSO** is already enabled. If it is not, enable it first.
4. Toggle **ON** the **SCIM Provisioning** setting.

### Phase 2: Mint a bearer token

**Duration**: 2 minutes

With SCIM enabled, generate the token your IdP will use to authenticate.

1. In the SCIM section of the authentication settings, click **Generate Token**.
2. **Copy the token immediately.** It is displayed only once and cannot be retrieved again.
3. Store it securely — you will paste it into your IdP in the next phase.

{% hint style="warning" %}
An organization has a **single active SCIM token** at a time. To rotate the token, generate a new one, update your IdP with it, then revoke the old one. Minting the new token first avoids an interruption in provisioning.
{% endhint %}

The token is pinned to the organization it was minted in — it can only ever read or write that one organization's users and teams.

### Phase 3: Configure your IdP

**Duration**: 5-10 minutes

In your IdP's provisioning configuration for the Duro application, set:

| Field                 | Value                                                                                                           |
| --------------------- | --------------------------------------------------------------------------------------------------------------- |
| SCIM version          | **SCIM 2.0**                                                                                                    |
| Authentication method | **HTTP Header / Bearer token**                                                                                  |
| SCIM base URL         | Your tenant's dedicated SCIM host — for example `https://scim-<tenant>.durohub.com/scim/v2` (no trailing slash) |
| Bearer token          | The token from Phase 2                                                                                          |

{% hint style="info" %}
Your exact SCIM host is specific to your Duro tenant — it takes the form `scim-<tenant>.durohub.com` and is **not** the API host used for GraphQL. If you are unsure of it, your Duro technical contact will confirm it. It always ends in `/scim/v2`.
{% endhint %}

Use your IdP's **Test Connection** action to confirm reachability. On success, activate provisioning. Most IdPs then run an initial sync of every user and group already assigned to the app.

### Phase 4: Map groups to teams and assign roles

**Duration**: varies

1. **Assign groups** to the Duro provisioning app in your IdP. Each assigned group is provisioned to Duro as a **team**, with its members added as team members.
2. **Assign roles in Duro.** For each provisioned team, a Duro administrator sets the team's organization role and any per-library overrides in Duro. This step is never performed by the IdP.

## Groups Map to Teams

A SCIM Group corresponds one-to-one with a Duro **Team**. Group membership drives team membership through standard SCIM operations:

| SCIM operation                                        | Duro effect                                                         |
| ----------------------------------------------------- | ------------------------------------------------------------------- |
| **Create Group** (`POST /Groups`)                     | Creates a new team                                                  |
| **Add / remove members** (`PATCH /Groups`)            | Adds or removes those users from the team                           |
| **Replace members** (`PUT /Groups`)                   | Replaces the team's entire membership                               |
| **Delete Group** (`DELETE /Groups`)                   | Archives the team                                                   |
| **Deactivate user** (`PATCH /Users`, `active: false`) | Removes the user from all teams, revoking their organization access |

Once a team exists, assign its organization role and library overrides in Duro. See [Team-Based Access Control](/advanced-topics/rbac.md#team-based-access-control) for how those roles resolve into a member's effective permissions.

### SCIM-managed teams are locked in the UI

To prevent drift between Duro and your IdP, teams that were provisioned via SCIM are **locked from manual structural edits** in the Duro UI. The IdP remains the single source of truth for a SCIM-managed team's shape.

| Locked (managed by the IdP)     | Allowed (managed in Duro)              |
| ------------------------------- | -------------------------------------- |
| Renaming the team               | Assigning the team's organization role |
| Adding or removing members      | Assigning per-library role overrides   |
| Archiving or restoring the team | Adjusting the team's library access    |

This split keeps the two systems from fighting each other: your IdP owns *who is on the team*, and Duro owns *what the team can do*.

## Deprovisioning

When a user is deactivated in your IdP — or removed from every group assigned to Duro — SCIM removes their team memberships. Because organization access flows through teams, removing those memberships revokes the user's access.

{% hint style="info" %}
**The user account persists after deprovisioning.** Rather than deleting the account, Duro retains it in a dormant state so historical records — authorship, change orders, comments — stay intact and attributable. Reactivating the user in your IdP restores their team memberships and access.
{% endhint %}

## Live Enforcement

The SCIM-enabled state is enforced **live, per request**. If SCIM is disabled for the organization — either directly, or as a cascade from disabling SAML — the bearer token stops authenticating immediately. Subsequent IdP requests receive `401 Unauthorized`.

## Testing Your Setup

1. **Confirm SAML is enabled** and SCIM shows as enabled in Org Settings → Authentication.
2. **Run your IdP's Test Connection** — it should succeed against the `/scim/v2` base URL.
3. **Assign a test user** to the Duro app in your IdP and confirm they appear as an active user in Duro.
4. **Assign a group with members** and confirm a matching team is created in Duro with the expected members.
5. **Assign a role to the team in Duro** and confirm a member's effective access reflects it.
6. **Deactivate the test user** in your IdP and confirm their access is revoked while the account remains.

## Troubleshooting

{% hint style="warning" %}
**IdP provisioning suddenly returns `401 Unauthorized`.** This is expected if SCIM was disabled, or if SAML was disabled (which cascades to disable SCIM). Re-enable SAML, then re-enable SCIM, and mint a fresh token if the old one was revoked. Token authentication is evaluated on every request, so the change takes effect immediately.
{% endhint %}

**Test Connection fails before any users sync**

* Verify the SCIM base URL ends in `/scim/v2` with no trailing slash.
* Confirm the bearer token was copied correctly and has not been revoked or rotated out.
* Confirm SCIM (and SAML) are both enabled for the organization.

**A team can't be renamed or edited in Duro**

* SCIM-managed teams are intentionally locked from structural edits. Make membership and naming changes in your IdP; assign roles and library access in Duro.

**A provisioned user can log in but sees no organization access**

* Access flows through teams. Confirm the user is a member of at least one provisioned team, and that the team has been assigned a role in Duro.

### Next Steps

Learn how team roles combine with a user's direct roles in [Role-Based Access Control](/advanced-topics/rbac.md#team-based-access-control).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.durohub.com/advanced-topics/scim-provisioning.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
