<!-- source: https://modelux.ai/docs/guides/scim -->

> Automate user lifecycle (create, update, deactivate) from your IdP using SCIM 2.0.

# SCIM user provisioning

SCIM 2.0 lets your IdP push user lifecycle events — create, update,
deactivate — into Modelux automatically. Without it, you manage seats
manually: when someone leaves the company, an admin has to remember to
remove them from Modelux.

SCIM is available on the **Enterprise** plan. You'll typically set it
up alongside [SAML SSO](/docs/guides/sso).

## What SCIM does in Modelux

Each SCIM "User" is a **membership** in your Modelux org:

- **Create** → add the user to your org. If they already have a Modelux
  account with the same verified email, we link to it.
- **Update / PATCH `active: false`** → mark the membership
  deactivated. The user can't sign in or use management API keys they
  created.
- **Update / PATCH `active: true`** → reactivate.
- **Delete** → remove the membership from your org. The user's global
  account (if shared with other orgs) is not deleted.

Role is transmitted via a Modelux SCIM extension:
`urn:modelux:params:scim:schemas:extension:2.0:User`. If your IdP
doesn't fill it, new members get the **default role** from your SSO
configuration.

## Create a SCIM token

1. In Modelux → **Settings → SSO**, scroll to the **SCIM tokens** card.
2. Click **Create token**. Give it a name like `Okta` or `Entra
   provisioning`.
3. Copy the token value — it starts with `mlx_scim_`. **It is shown
   exactly once.** If you lose it, revoke the token and create a new
   one.

The base URL your IdP will POST to is:

```
https://app.modelux.ai/api/scim/v2
```

## Okta

1. On your Modelux SAML app in Okta → **General → App Settings**,
   enable **Provisioning → SCIM** (requires the Lifecycle Management
   add-on).
2. **Base URL:** `https://app.modelux.ai/api/scim/v2`
3. **Unique identifier field for users:** `userName`
4. **Supported provisioning actions:** check Push New Users, Push
   Profile Updates, Push Groups are not used.
5. **Authentication Mode:** HTTP Header
6. **Authorization:** `Bearer <your-mlx_scim_ token>`
7. Click **Test API Credentials** — you should get a green checkmark.

On the **To App** settings, enable *Create Users*, *Update User
Attributes*, and *Deactivate Users*.

## Microsoft Entra ID

1. On your Modelux Enterprise app → **Provisioning → Get started →
   Automatic**.
2. **Tenant URL:** `https://app.modelux.ai/api/scim/v2`
3. **Secret token:** your `mlx_scim_...` token
4. Click **Test Connection** — Entra should report success.
5. Save, then under **Mappings → Provision Microsoft Entra ID Users**,
   confirm `userPrincipalName` or `mail` maps to `userName`, and the
   name/email attributes map to their SCIM equivalents.
6. Set **Provisioning Status** to **On** and save.

Entra provisioning cycles every ~40 minutes. Use **Provision on
demand** to test a single user immediately.

## Deactivation behavior

A SCIM `active: false` patch keeps the membership row but sets
`deactivatedAt`. This preserves the audit trail (when they were
deactivated, by which token) and keeps history intact. Reactivating
clears the flag; the user gets their previous role back.

A SCIM `DELETE /Users/<id>` removes the membership entirely. The
global `User` record stays — they may be a member of other Modelux
orgs, and their personal account (if any) shouldn't be collateral
damage.

## Last-owner protection

Modelux refuses to delete or deactivate the **last owner** of an org.
SCIM returns a `409 mutability` error. Add another owner first, or
contact support if you need a workaround.

## Testing

- Create a test user in your IdP, assign them to the Modelux app, and
  trigger provisioning manually. They should appear under **Settings →
  Team** within a few seconds (Okta) or minutes (Entra).
- Deactivate them in the IdP. They should appear in Modelux with a
  *deactivated* indicator and be unable to sign in.
- Reactivate and confirm they can sign in again.

## Auditing

Every SCIM mutation emits an audit event under
**Settings → Audit log**, scoped to the SCIM token that made the call.
