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

# Microsoft Entra ID provisioning

> Provision Modem users and groups automatically from Microsoft Entra ID with SCIM 2.0

This guide turns on automatic provisioning for the Modem enterprise application in Microsoft Entra ID. Read [Directory Sync](/docs/enterprise/scim) first if you haven't — it covers the token, roles, and the limits that apply whatever directory you use.

The Entra admin centre is redesigned regularly, so treat the menu paths and field labels below as a guide; the exact labels move between releases.

## Prerequisites

* [Enterprise SSO](/docs/enterprise/sso) already configured, using the **same enterprise application** — see [Microsoft Entra SAML](/docs/enterprise/sso-entra)
* Directory Sync enabled for your Modem organization, and the **owner** role in it
* An Entra role that can configure application provisioning, such as Application Administrator
* Entra ID P1 or P2, which is what includes automatic provisioning

<Warning>
  Set up single sign-on first, and finish it. Provisioning creates Modem accounts but no way to sign in, and the two have to agree on one
  identifier — see [Matching the SSO identity](#matching-the-sso-identity), which needs a change to Entra's default attribute mapping.
</Warning>

## Setup

<Steps>
  <Step title="Generate a token in Modem">
    In the [Modem dashboard](https://app.modem.dev), go to **Settings** → **Directory Sync** and click
    **Generate token**. Copy it — it is shown once. Copy the SCIM base URL from the same page:

    ```
    https://app.modem.dev/api/auth/scim/v2
    ```
  </Step>

  <Step title="Start automatic provisioning">
    In the Microsoft Entra admin centre, open **Enterprise applications**, select your Modem application, choose
    **Provisioning**, and set the provisioning mode to **Automatic**.
  </Step>

  <Step title="Enter the credentials and test the connection">
    Under **Admin Credentials**, set:

    | Field        | Value                                    |
    | ------------ | ---------------------------------------- |
    | Tenant URL   | `https://app.modem.dev/api/auth/scim/v2` |
    | Secret Token | the token you generated in Modem         |

    Click **Test Connection**. Entra fetches a user and a group to confirm the endpoint and the token are valid.
    Save once it passes; see [Troubleshooting](#troubleshooting) if it does not.
  </Step>

  <Step title="Point externalId at the object id">
    Open **Mappings** → **Provision Microsoft Entra ID Users** and change the attribute that flows to
    **`externalId`**.

    Entra's default sends `mailNickname`. That is **not** the value the SAML application asserts, so leaving it
    alone means every provisioned person gets a second Modem account the first time they sign in. Change the
    source attribute to **`objectId`** and save. See [Matching the SSO identity](#matching-the-sso-identity).
  </Step>

  <Step title="Set the provisioning scope">
    Under **Settings**, choose whether to provision **only assigned users and groups** (recommended) or everyone in
    the directory, then set **Provisioning Status** to **On**.
  </Step>

  <Step title="Assign people and the groups that should grant roles">
    On the application's **Users and groups** page, assign the people who should have Modem, and the groups you
    want to use for Modem roles — typically one group for admins. Assigned groups are provisioned to Modem along
    with their membership.

    Assign one person first and confirm they appear under **Provisioned people** on Modem's Directory Sync page
    before you assign everyone. Entra's initial cycle can take a while; **Provision on demand** runs a single
    person immediately, which is the fastest way to check the configuration.
  </Step>

  <Step title="Map the groups to Modem roles">
    Back on Modem's **Settings** → **Directory Sync** page, map each provisioned group to **Admin** or **Member**
    and save. Modem re-applies the mapping to everyone already provisioned.
  </Step>
</Steps>

## Matching the SSO identity

Modem links a provisioned directory record to the person signing in by comparing the SCIM **`externalId`** with the SAML **NameID**. Both must be the Entra **object id**:

| Half           | Where it is set                                                                         | Value           |
| -------------- | --------------------------------------------------------------------------------------- | --------------- |
| Single sign-on | SAML application → **Attributes & Claims** → **Unique User Identifier (Name ID)**       | `user.objectid` |
| Provisioning   | **Provisioning** → **Mappings** → **Provision Microsoft Entra ID Users** → `externalId` | `objectId`      |

<Warning>
  The provisioning half is **not** the default. Entra ships `mailNickname` as the source for `externalId`, which is a mutable alias and
  does not match the NameID. Change it to `objectId` before you provision anyone, or you will have two Modem accounts for every person and
  have to clean them up by hand.
</Warning>

### Confirming they match

<Steps>
  <Step title="Provision one person">
    Use **Provision on demand** for a test user, and confirm they appear under **Provisioned people** on Modem's Directory Sync page.
  </Step>

  <Step title="Have them sign in">Send them to `https://app.modem.dev` to sign in with **Continue with SSO**.</Step>

  <Step title="Check the count">
    Look at **Settings** → **Team**. If the identifiers match, they are the person the directory provisioned, in the role their groups
    grant. If they do not match, you will see **two** entries for the same human — one provisioned, one created at sign-in. Fix the
    `externalId` mapping and remove the extra account.
  </Step>
</Steps>

## Attribute mapping

Beyond the `externalId` change above, Entra's default user mapping works as shipped.

| What Modem uses | Entra attribute                         | Notes                                                        |
| --------------- | --------------------------------------- | ------------------------------------------------------------ |
| Account link    | `objectId` → `externalId`               | **Change this from the default.** Must equal the SAML NameID |
| Sign-in address | `userPrincipalName` → `userName`        | Entra's default                                              |
| Email           | `mail` → `emails[type eq "work"].value` | Falls back to `userName` when absent                         |
| Name            | `givenName`, `surname`, `displayName`   | Used for display only                                        |
| Active state    | `IsSoftDeleted` → `active`              | Entra's default. Do not remap it                             |

Everything else Entra sends — job title, phone numbers, addresses, and the Enterprise User extension (`department`, `employeeNumber`, `manager`) — is accepted and stored, and is not used to decide anyone's access.

Modem accepts the shapes Entra's provisioning client actually sends, including the `"True"` / `"False"` strings its default `active` mapping produces, its capitalised `Replace` and `Add` operations, and the legacy group-schema marker its classic client puts on group creates. There is nothing to configure for any of them.

## Testing the whole cycle

<Steps>
  <Step title="Provision on demand">
    Run **Provision on demand** for a test user. They appear under **Provisioned people** in Modem, and in **Settings** → **Team** as a
    member.
  </Step>

  <Step title="Promote">
    Add them to the Entra group you mapped to **Admin**, and provision that group. Their role in Modem changes to admin.
  </Step>

  <Step title="Sign in">Have them sign in with **Continue with SSO**, and confirm no second account appears.</Step>

  <Step title="Unassign">
    Remove the application assignment. Entra sends a soft delete on its next cycle; their access is revoked and their Modem membership
    is removed. Any session they had open stops working within five minutes.
  </Step>

  <Step title="Reassign">Assign it again. They come back, with the role their groups still grant.</Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Test Connection fails with 401">
    The token is wrong, expired, or revoked. Generate a fresh one in Modem and paste it again. Entra adds the `Bearer ` prefix itself,
    so paste only the token value.
  </Accordion>

  <Accordion title="Test Connection fails with 404 or cannot reach the endpoint">
    Check the Tenant URL: `https://app.modem.dev/api/auth/scim/v2`, with no trailing slash. Entra appends `/Users` and `/Groups` itself.
  </Accordion>

  <Accordion title="Every provisioned person gets a second account when they sign in">
    The `externalId` mapping is still Entra's default `mailNickname`. Change it to `objectId`, then re-provision. Existing duplicate
    accounts have to be removed by hand.
  </Accordion>

  <Accordion title="Provisioning is on but nothing happens">
    Entra runs on its own schedule, and the first cycle after enabling can take a long time. Use **Provision on demand** to test one
    person immediately, and check the provisioning logs for skipped users — the usual cause is that the scope is set to assigned users
    only and nobody is assigned.
  </Accordion>

  <Accordion title="A group fails to provision with an error about members">
    Modem accepts up to 1,000 direct members in a group, and users only. Split a larger group, and flatten any group that contains other
    groups — Entra sends nested groups as members, which Modem rejects.
  </Accordion>

  <Accordion title="Removing someone leaves their Modem access in place">
    Check that the mapping from `IsSoftDeleted` to `active` is intact, and wait for the next provisioning cycle. Entra sends the
    deactivation on a cycle rather than immediately.
  </Accordion>

  <Accordion title="Provisioning stops working after about a year">
    Tokens expire one year after they are generated. Rotate on Modem's Directory Sync page, paste the new value into Entra, re-run
    **Test Connection**, then revoke the old one.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Directory Sync" icon="https://mintcdn.com/modem-844d7a4a/Wr2r4IRr97lNQiQb/icons/shield.svg?fit=max&auto=format&n=Wr2r4IRr97lNQiQb&q=85&s=ee1ca3093fcbdf45ec5dc1a74652bed6" href="/docs/enterprise/scim" width="24" height="24" data-path="icons/shield.svg">
    The token, roles, lifecycle, and limits.
  </Card>

  <Card title="Microsoft Entra SAML" icon="https://mintcdn.com/modem-844d7a4a/Wr2r4IRr97lNQiQb/icons/shield.svg?fit=max&auto=format&n=Wr2r4IRr97lNQiQb&q=85&s=ee1ca3093fcbdf45ec5dc1a74652bed6" href="/docs/enterprise/sso-entra" width="24" height="24" data-path="icons/shield.svg">
    The single sign-on half, which has to be set up first.
  </Card>
</CardGroup>
