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

# SCIM Setup

> Configure SCIM provisioning for SkillsDB using Microsoft Entra ID, including the enterprise application, automatic provisioning, and attribute mapping.

<Info>
  **Quick Summary:** Set up SCIM provisioning between Microsoft Entra ID and SkillsDB by creating an Entra enterprise application, connecting it with the Tenant URL and Secret Token from SkillsDB, and mapping the required attributes.
</Info>

## Overview

SCIM provisioning automatically creates, updates, and deactivates SkillsDB user accounts based on changes in your identity provider (IdP). SkillsDB supports SCIM through Stytch, which receives SCIM events from your IdP and forwards them to SkillsDB as webhooks.

This guide covers the Microsoft Entra ID (Azure AD) setup path. If you use a different IdP, the concepts are the same but the UI steps differ — contact SkillsDB Support for guidance.

SCIM provisioning handles:

* Creating SkillsDB users when they are added to the SCIM application in Entra
* Updating user attributes (name, manager, contact information) when they change in Entra
* Assigning SkillsDB permission levels based on SCIM group membership
* Deactivating SkillsDB users when they are removed from the SCIM application or disabled in Entra

SCIM does not replace Single Sign-On (SSO). SSO authenticates users at sign-in; SCIM provisions their accounts. Most customers configure both.

## Prerequisites

Before you begin, make sure you have:

* **Permission level**: Microsoft Entra administrator access
* **Setup requirement**: A Tenant URL and Secret Token from SkillsDB Support
* **Access requirement**: The Entra admin center at **Identity > Applications > Enterprise applications**

## How to enable SCIM provisioning

<Steps>
  <Step title="Create the Entra enterprise application">
    Log into the **Microsoft Entra admin center**, navigate to **Enterprise applications**, and select to create a new application.

    Select **Create your own application** at the top.

    Name the application, select **Integrate any other application you don't find in the gallery (Non-gallery)**, and select **Create**.
  </Step>

  <Step title="Open the provisioning configuration">
    On the new application's overview page, select **Provisioning** from the left sidebar, or select **Provision User Accounts** under the **Getting Started** section.

    Under **Get Started > Create Configuration**, select **Connect your application**.

    Choose **Automatic** from the dropdown.
  </Step>

  <Step title="Provide the SkillsDB credentials">
    Under **New provisioning configuration**, get the **Tenant URL** and **Secret Token** from SkillsDB Support and add them to the corresponding fields, then select **Test Connection**.

    <Warning>
      **Warning:** Do not share the Secret Token. Anyone with this token can provision users into your SkillsDB instance.
    </Warning>
  </Step>

  <Step title="Map the externalId attribute">
    SCIM uses a stable external identifier to track users across systems. You must map Entra's `objectId` to the SCIM `externalId` attribute.

    1. On the left sidebar, under **Manage**, select **Provisioning**
    2. Select **Provision Microsoft Entra ID Users**
    3. In the **customappsso Attributes** table, locate the `externalId` record
    4. Update the **Source Attribute** to `objectId`
    5. Select **OK** and **Save**
  </Step>

  <Step title="Turn on provisioning">
    Back on the **Provisioning** page, turn **Provisioning Status** to **On**.
  </Step>

  <Step title="Provision users">
    Test the SCIM integration by assigning or removing people from the application and watching the changes propagate to your Stytch member records. Entra syncs automatically on a 40-minute timer; use **Provision on Demand** to speed up testing.
  </Step>
</Steps>

Once provisioning is on, Entra sends user and group changes to Stytch, which forwards them to SkillsDB. Changes appear in SkillsDB within one sync cycle.

## How SkillsDB maps SCIM groups to permission levels

SkillsDB recognizes two default SCIM groups. Add users to these groups in Entra to grant the corresponding permission level in SkillsDB:

| Entra group name       | SkillsDB permission level |
| ---------------------- | ------------------------- |
| `SkillsdbGlobalAdmins` | Admin                     |
| `SkillsdbFullAccess`   | Full Access               |

Users who are not in either default group receive the **Basic** permission level. Basic users with direct reports are automatically promoted to the **Manager** role.

Any other SCIM group you provision is auto-created in SkillsDB as a custom SCIM group with Basic permission. Administrators can upgrade these custom groups to Full Access or Admin, and attach career automations to them. See [SCIM Groups and Permissions](/identity-and-provisioning/scim-groups-and-permissions) for the complete model.

## SCIM attribute mapping

When a SCIM event provisions or updates a user, SkillsDB maps the SCIM payload from your identity provider in three ways:

* **Direct fields** are stored on the user's SkillsDB record itself.
* **Org schema attachments** are stored as company-level entities (Job Title, Country, City, Department, Division) and linked to the user. SkillsDB creates the entry under your company automatically the first time a value appears in a SCIM event.
* **Identity tracking fields** are set on the user record so SkillsDB knows the user came from SCIM and can be reconciled with Stytch on every subsequent event.
* **Group membership** (the `groups` array) drives the user's permission level rather than mapping to a single field. See [SCIM Groups and Permissions](/identity-and-provisioning/scim-groups-and-permissions) for the full resolution rules.

### Direct fields

| SCIM attribute                         | SkillsDB field             | Notes                                                                                                                   |
| -------------------------------------- | -------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `email_address`                        | Email Address              | Must be unique across the SkillsDB instance. Duplicates are rejected.                                                   |
| `name.given_name`                      | First Name                 | Falls back to the first portion of `display_name` if `given_name` is not provided.                                      |
| `name.family_name`                     | Last Name                  | Falls back to the remainder of `display_name`, then to a value derived from the email, then to `Missing`.               |
| `display_name`                         | First/Last Name (fallback) | Used only when `given_name` or `family_name` is missing.                                                                |
| `active`                               | Active status              | Boolean. When `false`, SkillsDB deactivates the user.                                                                   |
| `addresses[0].street_address`          | Address                    | Only the first address in the array is used.                                                                            |
| `addresses[0].region`                  | State/Province             | Only the first address in the array is used.                                                                            |
| `addresses[0].postal_code`             | Zip/Postal Code            | Only the first address in the array is used.                                                                            |
| `phone_numbers[type=work]`             | Business Phone             | The first entry with `type` set to `work`.                                                                              |
| `phone_numbers[type=mobile]`           | Mobile Phone               | The first entry with `type` set to `mobile`.                                                                            |
| `phone_numbers[type=fax]`              | Fax Number                 | The first entry with `type` set to `fax`.                                                                               |
| `enterprise_extension.manager.value`   | Manager                    | Resolves the manager by their SCIM member ID. If the manager is not yet in SkillsDB, SkillsDB creates them recursively. |
| `enterprise_extension.employee_number` | Personnel/Employee Number  | Stored on the user as their internal personnel identifier.                                                              |

### Org schema attachments

| SCIM attribute                    | SkillsDB attachment | Notes                                                                                                          |
| --------------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------- |
| `title`                           | Job Title           | SkillsDB creates the job title under your company if it does not already exist, then attaches it to the user.  |
| `addresses[0].country`            | Country             | SkillsDB creates the country under your company if it does not already exist, then attaches it to the user.    |
| `addresses[0].locality`           | City                | SkillsDB creates the city under your company if it does not already exist, then attaches it to the user.       |
| `enterprise_extension.department` | Department          | SkillsDB creates the department under your company if it does not already exist, then attaches it to the user. |
| `enterprise_extension.division`   | Division            | SkillsDB creates the division under your company if it does not already exist, then attaches it to the user.   |

### Identity tracking fields

| SCIM source                  | SkillsDB field         | Notes                                                                                                                                 |
| ---------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `member_id` (Stytch member)  | Stytch Member ID       | Used to match incoming SCIM events to the existing SkillsDB user. Set on initial provisioning.                                        |
| `organization_id` (Stytch)   | Stytch Organization ID | Identifies which Stytch organization the user belongs to. Set on initial provisioning.                                                |
| (derived)                    | SCIM Provisioned flag  | SkillsDB sets this flag to `true` so the user is treated as SCIM-managed. Surfaces in the People list filter as **SCIM Provisioned**. |
| (event timestamp, on create) | Date Added             | SkillsDB sets the user's date-added timestamp to the time of the initial SCIM creation event.                                         |

### Group membership

| SCIM source                          | SkillsDB effect                                                                                                                                                                                                                                                                                                    |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `groups` (array of group references) | Drives the user's effective permission level. Default groups (`SkillsdbGlobalAdmins`, `SkillsdbFullAccess`) and custom SCIM groups are evaluated against the user's memberships, and the highest permission level wins. See [SCIM Groups and Permissions](/identity-and-provisioning/scim-groups-and-permissions). |

If an attribute is not present in the SCIM payload, SkillsDB leaves the corresponding direct field unchanged on updates (and empty on initial creation, except where a fallback is documented above). Org schema attachments are similarly only updated when their source attribute is present.

## How to verify provisioning is working

After turning on provisioning in Entra, confirm that SkillsDB is receiving events.

<Steps>
  <Step title="Open the SkillsDB SSO & SCIM settings">
    In SkillsDB, navigate to **Settings > SSO & SCIM** and select **Configure SSO and SCIM settings**.
  </Step>

  <Step title="Check the Last SCIM sync indicator">
    The page header shows **Last SCIM sync: `<timestamp>`** when events are arriving. If it shows **Not yet synced**, no events have been received.
  </Step>

  <Step title="Confirm users are appearing">
    Select **Active Users** on either default group's row to see the users currently assigned to that group. The count updates as Entra provisions users.
  </Step>

  <Step title="Review the event log if something looks wrong">
    Select **Event Log** from the top of the SSO & SCIM page to see every provisioning event SkillsDB has received. See [SCIM Event Log](/identity-and-provisioning/scim-event-log) for how to read the log.
  </Step>
</Steps>

## Common Questions

<AccordionGroup>
  <Accordion title="How long does it take for an Entra change to appear in SkillsDB?">
    Entra syncs on a 40-minute cycle by default. Use **Provision on Demand** in Entra to push a specific user immediately. Once Entra sends the event, SkillsDB processes it within seconds.
  </Accordion>

  <Accordion title="What happens if I enable SCIM before mapping the externalId attribute?">
    Users provision correctly for the first sync but subsequent updates may not match the same SkillsDB user. Fix the mapping as soon as possible — the correction applies to future events. Existing user records do not need to be recreated.
  </Accordion>

  <Accordion title="Do I need SSO configured to use SCIM?">
    No. SCIM and SSO are independent. You can provision users via SCIM and have them sign in with username and password, or vice versa. Most customers configure both.
  </Accordion>

  <Accordion title="Can I use SCIM with Okta, OneLogin, or a different identity provider?">
    Yes. SkillsDB's SCIM layer is provider-agnostic because it runs through Stytch. Contact SkillsDB Support for the setup steps specific to your IdP — the concepts in this guide still apply, but the Entra-specific UI paths differ.
  </Accordion>

  <Accordion title="What happens to an existing SkillsDB user if their email matches a SCIM-provisioned user?">
    The SCIM event is rejected with an error because email must be unique. Delete or change the email on the existing SkillsDB user first, then re-run the SCIM sync.
  </Accordion>

  <Accordion title="Can I rotate the Tenant URL or Secret Token myself?">
    No. The Tenant URL and Secret Token are issued by Stytch and managed by SkillsDB Support. To rotate either credential, contact [SkillsDB Support](https://www.skillsdb.com/support) and request new credentials. Once you receive the new values, update them in your identity provider's SCIM configuration — the old values stop working as soon as Support issues the rotation.
  </Accordion>

  <Accordion title="What should I do if my Secret Token is exposed or compromised?">
    Treat an exposed Secret Token as a security incident — anyone with the token can provision, modify, or deactivate users in your SkillsDB instance. Contact [SkillsDB Support](https://www.skillsdb.com/support) immediately to rotate the token. While you wait for the new credentials, consider disabling provisioning in your identity provider to prevent any in-flight events from being trusted.
  </Accordion>

  <Accordion title="Where do City, Country, Department, Division, and Job Title come from in SCIM?">
    These are populated from `addresses[0].locality` (City), `addresses[0].country` (Country), `enterprise_extension.department`, `enterprise_extension.division`, and `title` in the SCIM payload. SkillsDB stores them as company-level org schema entries (not as fields directly on the user record) and attaches them to the user. If the entry does not yet exist for your company, SkillsDB creates it the first time it appears in a SCIM event.
  </Accordion>
</AccordionGroup>

## Related Articles

<CardGroup cols={2}>
  <Card title="SCIM Overview" icon="circle-info" href="/identity-and-provisioning/overview">
    How SCIM fits into the SkillsDB identity model alongside SSO.
  </Card>

  <Card title="SCIM Groups and Permissions" icon="users-gear" href="/identity-and-provisioning/scim-groups-and-permissions">
    Default groups, custom groups, and how permission levels are resolved.
  </Card>

  <Card title="Azure Sync Considerations" icon="triangle-exclamation" href="/identity-and-provisioning/azure-sync-considerations">
    Known Entra limitations and workarounds for email changes, manager assignment, and deactivation.
  </Card>

  <Card title="SCIM Event Log" icon="clipboard-list" href="/identity-and-provisioning/scim-event-log">
    Read the audit log to verify sync activity and troubleshoot issues.
  </Card>
</CardGroup>

## Need More Help?

If you run into issues during setup, reach out to your organization's SkillsDB administrator or contact [SkillsDB Support](https://www.skillsdb.com/support).
