> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sazabi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Set up SCIM

> Turn on SCIM for your SSO connection and connect Okta, Microsoft Entra ID, OneLogin, PingOne or another SCIM 2.0 identity provider to it.

Turn on SCIM for your SSO connection, then give your identity provider (IdP) the SCIM base URL and token. This page covers Okta, Microsoft Entra ID, OneLogin, PingOne and other SCIM 2.0 providers, and which identity providers can't send SCIM. You need to be a Sazabi **owner**, or use a secret key with permission to manage SSO (`can_manage_sso`), and an administrator at your IdP.

## Turn SCIM on

> [tab] Dashboard
>
> 1. Go to [**Settings > Single sign-on**](https://app.sazabi.com/settings/single-sign-on).
> 2. In the **SCIM provisioning** section, click **Turn on SCIM**.
> 3. Copy the token with **Copy SCIM token**, and paste it into your IdP.

> [tab] CLI
>
> Install and authenticate the CLI per [`/reference/cli`](https://docs.sazabi.com/reference/cli), then run:
>
> ```bash theme={"system"}
> sazabi sso scim enable                                    # Turn SCIM on and print the token
> sazabi sso scim enable --expires-at 2027-06-30T00:00:00Z  # The same, with a token that expires
> ```

Sazabi shows the token **once**; it stores only a hash and can't show it again. If you lose it, rotate the token.

Turning SCIM on needs a connection, and the connection's **Allow sign-in** must be on. If SCIM is already on, nothing changes and no token is shown; rotate the token to get a new one.

A token never expires unless you give it an expiry: from the CLI with `--expires-at`, a future date in ISO 8601, or in Terraform with `token_expires_at`. Owners get an email 14 days and again 1 day before the current token expires. Rotate it before then, and paste the new token into your IdP.

## Connect your identity provider

Sazabi matches people by the SSO subject and the SCIM `externalId`. On a connection nobody has signed in through yet, make both your IdP's immutable ID, so an email change never splits a person in two. If people already sign in through the app with an email name ID, keep it, and send the same email as `externalId` instead. See [SCIM provisioning](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#people-who-already-sign-in-through-sso).

Sazabi reads the person's address from the primary email, or from `userName` when no email is sent. The address must be on one of your verified domains (see [Add SSO domains](https://docs.sazabi.com/guides/administer/single-sign-on/domains.md)), and Sazabi matches people by email at SSO sign-in too. So use the person's email as `userName`, unless your IdP uses the immutable ID for both, as Okta does below.

Only the Okta steps have been tested against a live Sazabi organization. The others follow each vendor's documentation.

> [tab] Okta
>
> Use the Sazabi SAML 2.0 app you created in [Configure SSO](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md).
>
> | Okta field | Value |
> | - | - |
> | SCIM connector base URL | `https://api.platform.sazabi.com/api/auth/scim/v2` |
> | Unique identifier field for users | `userName` |
> | Authentication Mode | HTTP Header |
> | Authorization (Bearer) | The SCIM token from Sazabi |
>
> **Step 1**
>
> ### Choose SCIM
>
> In the Okta Admin Console, open the Sazabi app. On the **General** tab, edit **App Settings**, set **Provisioning** to **SCIM** and save. A **Provisioning** tab appears.
>
> **Step 2**
>
> ### Connect Okta to Sazabi
>
> On the **Provisioning** tab, open **Integration** and enter the values above. Under **Supported provisioning actions**, choose **Push New Users** and **Push Profile Updates**. Don't choose **Push Groups**: Sazabi doesn't support groups. Click **Test Connector Configuration**, then save.
>
> **Step 3**
>
> ### Choose what Okta sends
>
> Under **Provisioning > To App**, enable **Create Users**, **Update User Attributes** and **Deactivate Users**, then save. Leave **Sync Password** off; Sazabi accounts have no password.
>
> **Step 4**
>
> ### Map the Okta user ID
>
> Make the Okta user ID, which never changes, both the SSO subject and `externalId`:
>
> * **SSO subject:** on the app's **Sign On** tab, the **Application username format** is **Custom** with `user.getInternalProperty("id")`, as in Configure SSO. For OIDC, the subject is the `sub` claim, which Okta already sets to the user ID.
> * **`userName`:** Okta sends the application username, so it's the Okta user ID.
> * **Email and name:** Okta's default mappings send the email address, given name and family name.
> * **`externalId`:** without one, Sazabi uses the `userName`, the Okta user ID, as the identifier. To send it anyway, in **Directory > Profile Editor**, open the Sazabi app's user profile. If it has no attribute with the external name `externalId`, add one, then map it from the Okta user with `user.getInternalProperty("id")`.
>
> If people already sign in through this app with an email name ID, don't change it; map `externalId` to `user.profile.email` instead.
>
> **Step 5**
>
> ### Push the people already assigned
>
> Okta pushes people when they're assigned to the app. People assigned before you turned on provisioning aren't pushed, and **Force Sync** doesn't push them. On the **Assignments** tab, unassign each of them and assign them again.
>
> **What Okta sends**
>
> | Okta action | SCIM request | In Sazabi |
> | - | - | - |
> | Assign a person | `GET /Users?filter=userName eq "…"`, then `POST /Users` | Adds or adopts them. See [SCIM provisioning](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#how-people-are-matched). |
> | Change a profile | `PUT /Users/{id}` | Updates their name. A changed email is ignored. |
> | Unassign or deactivate a person | `PATCH /Users/{id}` with `active: false` | Removes their membership. See [SCIM provisioning](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#deactivation). |
> | Reassign or reactivate a person | `PATCH /Users/{id}` with `active: true` | Restores the membership SCIM removed. |
>
> **Common mistakes**
>
> * Expecting people assigned before provisioning was on to arrive. Unassign and reassign them.
> * Pasting the token with a `Bearer ` prefix into a field that adds one.
> * Turning on **Push Groups**. Group requests answer `501`.

> [tab] Microsoft Entra ID
>
> Use the Sazabi enterprise application you created in [Configure SSO](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md), with SAML. Over OIDC, Entra's `sub` claim isn't the object ID, so Sazabi can't match a person's first sign-in to their SCIM record by subject; it falls back to email, and with [SCIM only](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#scim-only) on, those first sign-ins are refused.
>
> | Entra field | Value |
> | - | - |
> | Provisioning Mode | Automatic |
> | Tenant URL | `https://api.platform.sazabi.com/api/auth/scim/v2` |
> | Secret Token | The SCIM token from Sazabi |
>
> **Step 1**
>
> ### Connect Entra to Sazabi
>
> In the Microsoft Entra admin center, open **Enterprise applications**, then the Sazabi app, then **Provisioning**. Set **Provisioning Mode** to **Automatic**, and under **Admin Credentials** enter the values above. Click **Test Connection**, then save.
>
> **Step 2**
>
> ### Map the attributes
>
> Under **Mappings**, turn off **Provision Microsoft Entra ID Groups**: Sazabi doesn't support groups. Then open **Provision Microsoft Entra ID Users** and set:
>
> | Sazabi attribute | Entra attribute |
> | - | - |
> | `userName` | `mail` (recommended), or `userPrincipalName` |
> | `externalId` | `objectId` |
> | `emails[type eq "work"].value` | `mail` |
> | `name.givenName` | `givenName` |
> | `name.familyName` | `surname` |
>
> Entra maps `userName` to `userPrincipalName` and `externalId` to `mailNickname` by default. We recommend `mail` for `userName`, because Entra looks people up by `userName` and Sazabi matches existing members by email. Keep `userPrincipalName` only if it's the same address as `mail`. Keep Entra's default mappings for `active` and `displayName`: Entra sends only the attributes that changed, and Sazabi updates a name from `name.givenName` and `name.familyName` only when both arrive together, so a change to one of them alone reaches Sazabi only through `displayName`.
>
> **Step 3**
>
> ### Match the SSO subject
>
> Under **Single sign-on > Attributes & Claims**, set **Unique User Identifier (Name ID)** to `user.objectid` with the persistent format, and add a claim named `email`, with no namespace, whose source is `user.mail`. If people already sign in through this app with an email name ID, don't change it; map `externalId` to the same attribute as the name ID, such as `mail`, instead.
>
> **Step 4**
>
> ### Limit the scope
>
> Under **Settings**, set **Scope** to **Sync only assigned users and groups**, so only the people assigned to the app reach Sazabi.
>
> **Step 5**
>
> ### Start provisioning
>
> Test one person first with **Provision on demand** (see [Verify provisioning](#verify-provisioning)). Then click **Start provisioning**, or set **Provisioning Status** to **On** under **Settings** and save. Entra's first cycle covers everyone assigned to the app and takes longer than later ones. After that, Entra syncs about every 40 minutes, so an assignment or unassignment can take that long to reach Sazabi.
>
> **What Entra sends**
>
> | Entra action | SCIM request | In Sazabi |
> | - | - | - |
> | Assign a person | `GET /Users?filter=userName eq "…"`, then `POST /Users` | Adds or adopts them. See [SCIM provisioning](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#how-people-are-matched). |
> | Change a user | `PATCH /Users/{id}` | Updates their name when Entra sends both name parts, or a changed `displayName`. A changed email is ignored. |
> | Unassign, disable or soft-delete a user | `PATCH /Users/{id}` with `active` `"False"` | Removes their membership. See [SCIM provisioning](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#deactivation). |
> | Permanently delete a user | `DELETE /Users/{id}` | Removes their membership if it isn't already, and hides the SCIM record. |
>
> **Common mistakes**
>
> * Leaving `externalId` mapped to `mailNickname`. People are matched by email instead of by object ID, and a rename can leave them unrecognized.
> * A `userName` on an `onmicrosoft.com` domain, or another domain that isn't verified in Sazabi. Those creates are refused with `400 invalidValue`.
> * Leaving **Provision Microsoft Entra ID Groups** on. Group requests answer `501`.

> [tab] OneLogin
>
> Add a **SCIM Provisioner with SAML** app from the OneLogin catalog and set up its SAML settings for your SSO connection, as in [Configure SSO](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md) under Other SAML 2.0.
>
> | OneLogin field (Configuration tab) | Value |
> | - | - |
> | SCIM Base URL | `https://api.platform.sazabi.com/api/auth/scim/v2` |
> | SCIM Bearer Token | The SCIM token from Sazabi |
> | SCIM JSON Template | Keep OneLogin's default |
>
> OneLogin's default template sends no `externalId`, so Sazabi uses each person's `userName` as their identifier. Keep the SAML name ID the same value as `userName`, so a person's SSO sign-in matches their SCIM record. If OneLogin later sends an `externalId`, it replaces the `userName` stand-in once.
>
> **Step 1**
>
> ### Connect OneLogin to Sazabi
>
> On the app's **Configuration** tab, enter the values above and save. Then click **Enable**. OneLogin looks up a user it knows doesn't exist; when Sazabi answers with no match, the API status shows **Enabled**.
>
> **Step 2**
>
> ### Choose what OneLogin sends
>
> On the **Provisioning** tab, select **Enable provisioning for** the app. In the admin-approval options, clear **Create user**, **Delete user** and **Update user** so changes go out without approval, or keep them to approve each one under **Users > Provisioning**. Set **When users are deleted in OneLogin** to **Suspend** or **Delete**, then save.
>
> **Step 3**
>
> ### Give people access
>
> OneLogin provisions the people who get access to the app, usually through a role on the app's **Access** tab.
>
> **What OneLogin sends**
>
> | OneLogin action | SCIM request | In Sazabi |
> | - | - | - |
> | Give a person access | `GET /Users?filter=userName eq "…"`, then `POST /Users` | Adds or adopts them. |
> | Change a user | An update to `/Users/{id}` | Updates their name. A changed email is ignored. |
> | Suspend a user | An update with `active: false` | Removes their membership. |
> | Delete a user, with **Delete** chosen | `DELETE /Users/{id}` | Removes their membership if it isn't already, and hides the SCIM record. |

> [tab] JumpCloud
>
> JumpCloud's custom SCIM integration can provision Sazabi; it hasn't been tested with Sazabi. When JumpCloud sends no `externalId`, Sazabi uses each person's `userName` as their identifier, and if JumpCloud later sends an `externalId`, it replaces that stand-in once. A person is matched to their SSO sign-in only if your JumpCloud SAML app sends the same identifier as the subject.
>
> | JumpCloud field (Provisioning tab) | Value |
> | - | - |
> | Base URL | `https://api.platform.sazabi.com/api/auth/scim/v2` |
> | Token | The SCIM token from Sazabi |
> | Test User Email | An address on a verified domain that has no Sazabi account. Activation adds it to your organization with the default role and then removes it, so it needs a free seat, and the account it creates stays. |
>
> On the Sazabi SAML app in **Access > SSO Applications**, open the **Provisioning** tab, enter the values above and click **Test Connection**. Turn off **Enable management of User Groups and Group Membership in this application**: Sazabi doesn't support groups. Then click **Activate**. JumpCloud creates, updates and deletes its test user, then provisions the users bound to the app.
>
> If it doesn't work for you, use **Add people on their first sign-in** on your SSO connection instead, and remove people on [**Settings > Members**](https://app.sazabi.com/settings/members). See [Adding people on first sign-in](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md#adding-people-on-first-sign-in).

> [tab] PingOne
>
> Set up SSO first as in [Configure SSO](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md), then add an outbound SCIM connection and a rule that pushes people to it.
>
> | PingOne field | Value |
> | - | - |
> | SCIM Base URL | `https://api.platform.sazabi.com/api/auth/scim/v2` |
> | Users Resource | `/Users` |
> | SCIM Version | 2.0 |
> | Authentication Method | OAuth 2 Bearer Token |
> | OAuth Access Token | The SCIM token from Sazabi |
> | Auth Type Header | Bearer |
> | User Identifier | `userName` |
> | User filter expression | `userName eq "%s"` |
>
> **Step 1**
>
> ### Create the connection
>
> In the PingOne admin console, go to **Integrations > Provisioning**, click **+**, then **New Connection**. On the **Identity Store** line, click **Select**, choose the **SCIM Outbound** tile and name the connection. Under **Configure Authentication**, enter the values above and click **Test connection**.
>
> **Step 2**
>
> ### Choose what PingOne sends
>
> Under **Configure Preferences** and **Users Actions**, enter the user identifier and filter above. Select **Enable users creation**, **Enable users updation** and **Enable users disable**, and optionally **Enable users deprovision**. Don't add groups: Sazabi doesn't support them. Save, then turn the connection on with the toggle.
>
> **Step 3**
>
> ### Create the rule
>
> Under **Integrations > Provisioning**, click **+**, then **New Rule**. Set **Sync Direction** to **PingOne as Source** and choose the connection as the target. Under **User Filter**, choose who to push, for example a population or group.
>
> **Step 4**
>
> ### Map the attributes
>
> In the **Attribute Mapping** panel, map the PingOne email to `userName` and to the work email, the given and family names to `name.givenName` and `name.familyName`, and, if the target attributes offer `externalId`, map it from the same attribute your SSO connection sends as the subject. Without `externalId`, Sazabi uses the `userName`, the email, as the identifier, so a person's SSO sign-in matches it only if your SSO connection sends the email as the subject; with [SCIM only](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#scim-only) on, anyone else is refused. Save, then turn the rule on with the toggle.
>
> PingOne pushes the people its rule's user filter includes: it creates them, updates them when they change, disables them when they're disabled, and, with deprovisioning on, removes or disables them when they're deleted.

> [tab] Other SCIM 2.0
>
> Any other identity provider that provisions over SCIM 2.0 can use the same endpoint. Your IdP's docs say where each value goes.
>
> | Setting | Value |
> | - | - |
> | SCIM base URL | `https://api.platform.sazabi.com/api/auth/scim/v2` |
> | Authentication | Bearer token: the header `Authorization: Bearer <SCIM token>`. OAuth isn't supported. |
> | Resources | Users only, at `/Users`. Groups, Bulk and Me answer `501`, so turn off group provisioning. |
> | User requests | `GET /Users` with `filter=userName eq "…"` or `filter=externalId eq "…"`, `GET`, `PUT`, `PATCH` and `DELETE` on `/Users/{id}`, and `POST /Users` |
> | Discovery | `/ServiceProviderConfig`, `/ResourceTypes` and `/Schemas` |
>
> Sazabi reads these attributes:
>
> | Attribute | How Sazabi uses it |
> | - | - |
> | `userName` | Required, and unique on the connection. It's the person's email when `emails` is missing. |
> | `externalId` | Optional. Matches the person to their SSO sign-in: make it your IdP's immutable ID, the same value your SSO connection sends as the subject. A create without one uses the `userName` as a stand-in, which the first `externalId` your IdP sends later, in a `PUT`, a `PATCH` or a create matched by email, replaces once, unless another SCIM record already has it. Otherwise updates never change it. |
> | `emails` | The primary email, or the only one, is the person's address. It must be on one of your verified domains. Changes after the create are ignored. |
> | `name.givenName`, `name.familyName`, `name.formatted`, `displayName` | The person's name: the given and family names together, else `name.formatted`, else `displayName`. In a `PATCH`, the given and family names count only when both are sent. |
> | `active` | `false` removes the membership and `true` restores it. A Boolean in `POST` and `PUT`; `PATCH` also accepts `"True"` and `"False"`. |
>
> Sazabi matches a person by `externalId` and SSO subject first, then by email on a verified domain. A `userName` lookup adopts an existing member only when the `userName` is their email. See [How people are matched](https://docs.sazabi.com/guides/administer/single-sign-on/scim.md#how-people-are-matched).

## SCIM support by identity provider

Some identity providers can't push SCIM to a custom app. With those, turn on **Add people on their first sign-in** on your SSO connection, so people join at their first SSO sign-in, and remove people on [**Settings > Members**](https://app.sazabi.com/settings/members). See [Adding people on first sign-in](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md#adding-people-on-first-sign-in).

| Identity provider | SCIM to Sazabi | Instead |
| - | - | - |
| Okta | Yes | |
| Microsoft Entra ID | Yes | |
| OneLogin | Yes, with its default template | |
| PingOne | Not confirmed: untested with Sazabi | First sign-in |
| JumpCloud | Yes, untested with Sazabi | |
| Google Workspace | Only Google's catalog apps; custom SCIM profiles for other SAML apps are a limited beta, untested with Sazabi | First sign-in |
| Rippling | Not confirmed: Rippling's public docs don't describe it | First sign-in |
| AWS IAM Identity Center | No: its docs describe receiving SCIM from an IdP, not sending it to apps | First sign-in |
| Auth0 | No: its docs describe inbound SCIM only | First sign-in |
| Keycloak | No: its docs describe a SCIM API for its own users, not sending SCIM to apps | First sign-in |

> [!NOTE]
>
> **Google Workspace**
>
> Google sends SCIM only to the apps in its automated-provisioning catalog, which doesn't include Sazabi. With Google, people join on their first SSO sign-in, and you remove them on [**Settings > Members**](https://app.sazabi.com/settings/members): turning the Sazabi app off for someone in Google stops their SSO sign-ins, but they stay a member.

## Verify provisioning

> [tab] Okta
>
> Assign a test person on a verified domain to the app in Okta.

> [tab] Microsoft Entra ID
>
> On the app's **Provisioning** page, choose **Provision on demand**, pick a test user assigned to the app, and click **Provision**. Entra shows each step's result. Then start provisioning for everyone.

> [tab] OneLogin
>
> Give a test person on a verified domain access to the app. If you kept admin approval on, approve the task under **Users > Provisioning**.

> [tab] PingOne
>
> Add a test person on a verified domain to the rule's user filter, then check the rule's sync status.

> [tab] Other SCIM 2.0
>
> Assign a test person on a verified domain to the app in your IdP.

The person appears on [**Settings > Members**](https://app.sazabi.com/settings/members) with the connection's default role, and **Last change received** in the **SCIM provisioning** section of [**Settings > Single sign-on**](https://app.sazabi.com/settings/single-sign-on) updates. Then have them sign in through SSO.

## Further reading

> [card] [Configure SSO](https://docs.sazabi.com/guides/administer/single-sign-on/setup.md)
>
> Create the SSO connection SCIM runs on.

> [card] [Troubleshooting SCIM](https://docs.sazabi.com/guides/administer/single-sign-on/scim-troubleshooting.md)
>
> What each SCIM error means and what to do.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.