mobieusKnow mobieusLearn SCIM 2.0 — IdP setup guide History #100
Author
Patrick Bass
Submitted
Jun 3, 2026 6:28pm
Reviewed
Jun 3, 2026 6:28pm
Summary
Initial SCIM setup guide — Okta / Entra / Workday
# mobieusLearn SCIM 2.0 — IdP setup guide
SCIM (System for Cross-domain Identity Management) lets your enterprise identity provider — Okta, Microsoft Entra ID (Azure AD), Workday, OneLogin, Google Cloud Identity — push users and group memberships into your mobieusLearn tenant. Members get provisioned, deprovisioned, and updated automatically. No CSV uploads, no manual invites, no stale accounts.
+ This guide assumes you have admin access to both your IdP and to **/admin/learn/scim-credentials** on your tenant.
This guide assumes SCIM is included in your plan, and that you have admin access to both your IdP and to **/admin/learn/scim-credentials** on your tenant. SCIM is part of mobieusLearn's enterprise tier; if you don't see the credentials screen, contact support to confirm your plan includes SCIM provisioning.
## What gets synced
SCIM owns the **member** rung of the role hierarchy on your tenant — registered members (role=2) and banned members (role=1). The IdP can:
+ - Create users (mapped to `users.scim_external_id`)
- Create users
- Update user attributes (email, name, external id)
- Deactivate users (`active=false` flips role to 1=banned)
- Reactivate users (`active=true` lifts role back to 2=registered)
+ - Provision groups (mapped to `learn_cohorts` with `source='api'`)
+ - Sync group membership (mapped to `learn_cohort_members`)
- Provision groups (mapped to mobieusLearn cohorts)
- Sync group membership
The IdP **cannot** modify moderators, admins, or super-admins. Promoting a member past role 2 is a manual action inside Mobieus; SCIM PATCH requests that target a moderator or admin return `404 notFound` from the SCIM surface (without revealing the user exists).
+ The IdP **cannot** scrape your local-account directory either. SCIM `GET /Users` returns only `scim_managed=1` rows — manually-created tenant accounts never appear in the response.
The IdP **cannot** scrape your local-account directory either. SCIM `GET /Users` returns only SCIM-managed members — manually-created tenant accounts never appear in the response.
## Step 1 — Issue a bearer credential
1. Sign in to your tenant as a Tenant Admin
2. Go to **`/admin/learn/scim-credentials`**
3. Click **Issue credential**, give it a descriptive name (e.g. *"Okta production"*) and an optional slug
+ 4. **Copy the token immediately.** It's shown exactly once. The platform stores only the SHA-256 hash; a lost token means revoke + re-issue.
4. **Copy the token immediately.** It's shown exactly once. The platform stores only a hash of it; a lost token means revoke and re-issue.
The token format is `ms_scim_<base64url>`. Treat it like any other production secret — store it in your IdP's secret manager, never in source code.
## Step 2 — Connect your IdP
The SCIM base URL is `https://YOUR-TENANT.mobieus.io/scim/v2`.
### Okta
1. **Admin → Applications → Browse App Catalog →** create a **SCIM 2.0 Test App (Bearer Token)** or use your existing Mobieus app
2. **Provisioning → Integration**
- **SCIM connector base URL:** `https://YOUR-TENANT.mobieus.io/scim/v2`
- **Unique identifier field for users:** `userName`
- **Supported provisioning actions:** *Push New Users*, *Push Profile Updates*, *Push Groups*
- **Authentication mode:** *HTTP Header*
- **Authorization:** `Bearer ms_scim_…`
3. Click **Test API Credentials**. You should see *"App Profile Settings have been updated successfully."*
4. **To App →** enable *Create Users*, *Update User Attributes*, *Deactivate Users*. Save.
### Microsoft Entra ID (Azure AD)
1. **Enterprise applications →** create or open your Mobieus app
2. **Provisioning → Get started → Provisioning Mode:** *Automatic*
3. **Admin Credentials**
- **Tenant URL:** `https://YOUR-TENANT.mobieus.io/scim/v2`
- **Secret Token:** your `ms_scim_…` bearer
4. **Test Connection.** You should see *"The supplied credentials are authorized to enable provisioning."*
5. **Mappings → Provision Microsoft Entra ID Users:** ensure `userPrincipalName → userName`, `mail → emails[type eq "work"].value`, `givenName → name.givenName`, `surname → name.familyName`, `Switch([IsSoftDeleted], , "False", "True", "True", "False") → active`
6. **Settings → Provisioning Status:** *On*. Save.
### Workday
1. **Workday Studio →** add a new SCIM endpoint
2. **Endpoint URL:** `https://YOUR-TENANT.mobieus.io/scim/v2`
3. **Auth:** Bearer token, paste `ms_scim_…`
+ 4. Map your Workday worker fields to SCIM attributes (the same set as the Okta + Entra examples above)
4. Map your Workday worker fields to SCIM attributes (the same set as the Okta and Entra examples above)
5. Schedule the integration (Workday recommends every 30-60 minutes for SCIM)
### Test the connection from a terminal
Before turning on provisioning, verify the credential works:
```bash
curl -H "Authorization: Bearer ms_scim_..." \
https://YOUR-TENANT.mobieus.io/scim/v2/ServiceProviderConfig
```
Expected response (200, `application/scim+json`):
```json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
"patch": {"supported": true},
"bulk": {"supported": false},
+ "filter": {"supported": true, "maxResults": 200},
+ ...
"filter": {"supported": true, "maxResults": 200}
}
```
+ A `401` means the token is wrong, revoked, or the feature flag (`learn_scim`) isn't on for your tenant — check **`/admin/ai`** under the mobieusLearn group.
A `401` means the token is wrong or revoked. A `404` means SCIM isn't active for your tenant — confirm your plan includes mobieusLearn SCIM, or contact support to enable it.
## Step 3 — Push your first user
Once provisioning is on, your IdP will start pushing users. Verify on Mobieus:
1. **`/admin/learn/scim-credentials → click your credential`**
+ 2. The detail page shows the last 100 audit rows: method, path, status, response time, IP
2. The detail page shows the most recent requests: method, path, status, response time, IP
3. The status histogram (2xx / 4xx / 5xx) lights up green within ~30 seconds of the first push
4. **`/admin/users`** shows the new member with the `SCIM` badge
## Group → cohort mapping
+
+ When your IdP creates a SCIM Group, Mobieus creates a row in `learn_cohorts` with:
+
+ - `source = 'api'`
+ - `source_reference = <Group externalId>`
+ - `name = <displayName>`
+ - `owner_user_id` = the lowest-id super-admin (role=5) in your tenant
+ The owner attribution is automatic so the cohorts table's required `owner_user_id` constraint is satisfied. If your tenant has no super-admin, the SCIM Group create call returns `503 unavailable` with the message *"no super-admin to own SCIM-provisioned cohorts"* — create at least one role-5 user before turning on group sync.
When your IdP creates a SCIM Group, Mobieus creates a mobieusLearn cohort tied to that group's external id, named after the group's display name. The cohort is automatically owned by the lowest-id super-admin (role=5) in your tenant so the ownership requirement is satisfied. If your tenant has no super-admin, the SCIM Group create call returns `503 unavailable` with the message *"no super-admin to own SCIM-provisioned cohorts"* — create at least one role-5 user before turning on group sync.
## Email verification (anti-hijacking)
+ SCIM-created users land with `email_verified_at = NULL`. The legitimate owner of the email address still has to go through the regular verification flow before any privileged action. The IdP controls the row but **not** the email's ownership claim.
SCIM-created users land unverified. The legitimate owner of the email address still has to go through the regular verification flow before any privileged action. The IdP controls the account but **not** the email's ownership claim.
This is intentional. A malicious or compromised IdP could otherwise pre-claim email addresses that don't belong to it.
## Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
+ | `404` on `/scim/v2/ServiceProviderConfig` | `learn_scim` flag is off for your tenant | Enable on `/admin/ai` |
| `404` on `/scim/v2/ServiceProviderConfig` | SCIM isn't active for your tenant | Confirm your plan includes mobieusLearn SCIM, or contact support to enable it |
| `401 invalid_token` | Wrong, revoked, or disabled credential | Re-issue from `/admin/learn/scim-credentials` |
+ | `404 notFound` on PATCH a known user | User is not SCIM-managed, or has role > 2 | SCIM only manages its own rows. Promote the user via the Mobieus admin UI, not via SCIM |
| `404 notFound` on PATCH a known user | User is not SCIM-managed, or has role > 2 | SCIM only manages its own members. Promote the user via the Mobieus admin UI, not via SCIM |
| `503 unavailable` on Group create | No super-admin to attribute ownership to | Create a role-5 super-admin user |
+ | `409 uniqueness` on User create | `externalId` already exists | Pick a different `externalId` or PATCH the existing row |
| `409 uniqueness` on User create | `externalId` already exists | Pick a different `externalId` or PATCH the existing user |
## Audit retention
+
+ Every SCIM request lands in `learn_scim_audit` — method, path, body hash (never the body itself), status, response time, IP. Rows are kept indefinitely. The body hash lets you verify "did the IdP send X" without storing the body content.
+
+ The credential detail page shows the last 100 rows; export older history via the public API or by running:
+ ```sql
+ SELECT * FROM learn_scim_audit
+ WHERE credential_id = <id> AND created_at >= NOW() - INTERVAL 30 DAY
+ ORDER BY id DESC;
+ ```
Every SCIM request is recorded — method, path, status, response time, and IP — without storing the request body. The credential detail page shows the most recent requests; pull older history through the public API.
## Rotating a credential
1. Issue a new credential on `/admin/learn/scim-credentials`
2. Update your IdP's auth header to the new token
+ 3. Verify a successful sync (the new credential's audit log should start filling in)
3. Verify a successful sync (the new credential's request log should start filling in)
4. Revoke the old credential
+ There's no rolling-key support — Mobieus accepts only the credential whose SHA-256 matches what the IdP sends. Plan the cutover during a quiet provisioning window.
There's no rolling-key support — Mobieus accepts only the credential the IdP currently sends. Plan the cutover during a quiet provisioning window.
## When to NOT use SCIM
SCIM is overkill for tenants under ~50 members. The manual invite flow on `/admin/users` is faster to set up and easier to debug. SCIM pays off when:
- You're already running an IdP for other apps (Okta, Entra, Workday)
- New hires need access automatically on day one
- Former employees need access cut off immediately
+ - You want group membership to mirror your IdP's groups in `learn_cohorts`
- You want group membership to mirror your IdP's groups in mobieusLearn cohorts
For a tenant under that threshold, the manual flow is probably the right call.
---
+ *Tracked under feature key `learn_scim` (Phase 4 M6). Per ADR-0047. Endpoint surface in `/scim/v2/*` per RFC 7643/7644.*
*Tracked under feature key `learn_scim`. Endpoint surface at `/scim/v2/*`, conforming to RFC 7643/7644.*

mobieusLearn SCIM 2.0 — IdP setup guide

SCIM (System for Cross-domain Identity Management) lets your enterprise identity provider — Okta, Microsoft Entra ID (Azure AD), Workday, OneLogin, Google Cloud Identity — push users and group memberships into your mobieusLearn tenant. Members get provisioned, deprovisioned, and updated automatically. No CSV uploads, no manual invites, no stale accounts.

This guide assumes you have admin access to both your IdP and to /admin/learn/scim-credentials on your tenant.

What gets synced

SCIM owns the member rung of the role hierarchy on your tenant — registered members (role=2) and banned members (role=1). The IdP can:

  • Create users (mapped to users.scim_external_id)
  • Update user attributes (email, name, external id)
  • Deactivate users (active=false flips role to 1=banned)
  • Reactivate users (active=true lifts role back to 2=registered)
  • Provision groups (mapped to learn_cohorts with source='api')
  • Sync group membership (mapped to learn_cohort_members)

The IdP cannot modify moderators, admins, or super-admins. Promoting a member past role 2 is a manual action inside Mobieus; SCIM PATCH requests that target a moderator or admin return 404 notFound from the SCIM surface (without revealing the user exists).

The IdP cannot scrape your local-account directory either. SCIM GET /Users returns only scim_managed=1 rows — manually-created tenant accounts never appear in the response.

Step 1 — Issue a bearer credential

  1. Sign in to your tenant as a Tenant Admin
  2. Go to /admin/learn/scim-credentials
  3. Click Issue credential, give it a descriptive name (e.g. "Okta production") and an optional slug
  4. Copy the token immediately. It's shown exactly once. The platform stores only the SHA-256 hash; a lost token means revoke + re-issue.

The token format is ms_scim_<base64url>. Treat it like any other production secret — store it in your IdP's secret manager, never in source code.

Step 2 — Connect your IdP

The SCIM base URL is https://YOUR-TENANT.mobieus.io/scim/v2.

Okta

  1. Admin → Applications → Browse App Catalog → create a SCIM 2.0 Test App (Bearer Token) or use your existing Mobieus app
  2. Provisioning → Integration
    • SCIM connector base URL: https://YOUR-TENANT.mobieus.io/scim/v2
    • Unique identifier field for users: userName
    • Supported provisioning actions: Push New Users, Push Profile Updates, Push Groups
    • Authentication mode: HTTP Header
    • Authorization: Bearer ms_scim_…
  3. Click Test API Credentials. You should see "App Profile Settings have been updated successfully."
  4. To App → enable Create Users, Update User Attributes, Deactivate Users. Save.

Microsoft Entra ID (Azure AD)

  1. Enterprise applications → create or open your Mobieus app
  2. Provisioning → Get started → Provisioning Mode: Automatic
  3. Admin Credentials
    • Tenant URL: https://YOUR-TENANT.mobieus.io/scim/v2
    • Secret Token: your ms_scim_… bearer
  4. Test Connection. You should see "The supplied credentials are authorized to enable provisioning."
  5. Mappings → Provision Microsoft Entra ID Users: ensure userPrincipalName → userName, mail → emails[type eq "work"].value, givenName → name.givenName, surname → name.familyName, Switch([IsSoftDeleted], , "False", "True", "True", "False") → active
  6. Settings → Provisioning Status: On. Save.

Workday

  1. Workday Studio → add a new SCIM endpoint
  2. Endpoint URL: https://YOUR-TENANT.mobieus.io/scim/v2
  3. Auth: Bearer token, paste ms_scim_…
  4. Map your Workday worker fields to SCIM attributes (the same set as the Okta + Entra examples above)
  5. Schedule the integration (Workday recommends every 30-60 minutes for SCIM)

Test the connection from a terminal

Before turning on provisioning, verify the credential works:

curl -H "Authorization: Bearer ms_scim_..." \
     https://YOUR-TENANT.mobieus.io/scim/v2/ServiceProviderConfig

Expected response (200, application/scim+json):

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
  "patch":  {"supported": true},
  "bulk":   {"supported": false},
  "filter": {"supported": true, "maxResults": 200},
  ...
}

A 401 means the token is wrong, revoked, or the feature flag (learn_scim) isn't on for your tenant — check /admin/ai under the mobieusLearn group.

Step 3 — Push your first user

Once provisioning is on, your IdP will start pushing users. Verify on Mobieus:

  1. /admin/learn/scim-credentials → click your credential
  2. The detail page shows the last 100 audit rows: method, path, status, response time, IP
  3. The status histogram (2xx / 4xx / 5xx) lights up green within ~30 seconds of the first push
  4. /admin/users shows the new member with the SCIM badge

Group → cohort mapping

When your IdP creates a SCIM Group, Mobieus creates a row in learn_cohorts with:

  • source = 'api'
  • source_reference = <Group externalId>
  • name = <displayName>
  • owner_user_id = the lowest-id super-admin (role=5) in your tenant

The owner attribution is automatic so the cohorts table's required owner_user_id constraint is satisfied. If your tenant has no super-admin, the SCIM Group create call returns 503 unavailable with the message "no super-admin to own SCIM-provisioned cohorts" — create at least one role-5 user before turning on group sync.

Email verification (anti-hijacking)

SCIM-created users land with email_verified_at = NULL. The legitimate owner of the email address still has to go through the regular verification flow before any privileged action. The IdP controls the row but not the email's ownership claim.

This is intentional. A malicious or compromised IdP could otherwise pre-claim email addresses that don't belong to it.

Troubleshooting

Symptom Cause Fix
404 on /scim/v2/ServiceProviderConfig learn_scim flag is off for your tenant Enable on /admin/ai
401 invalid_token Wrong, revoked, or disabled credential Re-issue from /admin/learn/scim-credentials
404 notFound on PATCH a known user User is not SCIM-managed, or has role > 2 SCIM only manages its own rows. Promote the user via the Mobieus admin UI, not via SCIM
503 unavailable on Group create No super-admin to attribute ownership to Create a role-5 super-admin user
409 uniqueness on User create externalId already exists Pick a different externalId or PATCH the existing row

Audit retention

Every SCIM request lands in learn_scim_audit — method, path, body hash (never the body itself), status, response time, IP. Rows are kept indefinitely. The body hash lets you verify "did the IdP send X" without storing the body content.

The credential detail page shows the last 100 rows; export older history via the public API or by running:

SELECT * FROM learn_scim_audit
 WHERE credential_id = <id> AND created_at >= NOW() - INTERVAL 30 DAY
 ORDER BY id DESC;

Rotating a credential

  1. Issue a new credential on /admin/learn/scim-credentials
  2. Update your IdP's auth header to the new token
  3. Verify a successful sync (the new credential's audit log should start filling in)
  4. Revoke the old credential

There's no rolling-key support — Mobieus accepts only the credential whose SHA-256 matches what the IdP sends. Plan the cutover during a quiet provisioning window.

When to NOT use SCIM

SCIM is overkill for tenants under ~50 members. The manual invite flow on /admin/users is faster to set up and easier to debug. SCIM pays off when:

  • You're already running an IdP for other apps (Okta, Entra, Workday)
  • New hires need access automatically on day one
  • Former employees need access cut off immediately
  • You want group membership to mirror your IdP's groups in learn_cohorts

For a tenant under that threshold, the manual flow is probably the right call.


Tracked under feature key learn_scim (Phase 4 M6). Per ADR-0047. Endpoint surface in /scim/v2/* per RFC 7643/7644.

# mobieusLearn SCIM 2.0 — IdP setup guide

SCIM (System for Cross-domain Identity Management) lets your enterprise identity provider — Okta, Microsoft Entra ID (Azure AD), Workday, OneLogin, Google Cloud Identity — push users and group memberships into your mobieusLearn tenant. Members get provisioned, deprovisioned, and updated automatically. No CSV uploads, no manual invites, no stale accounts.

This guide assumes you have admin access to both your IdP and to **/admin/learn/scim-credentials** on your tenant.

## What gets synced

SCIM owns the **member** rung of the role hierarchy on your tenant — registered members (role=2) and banned members (role=1). The IdP can:

- Create users (mapped to `users.scim_external_id`)
- Update user attributes (email, name, external id)
- Deactivate users (`active=false` flips role to 1=banned)
- Reactivate users (`active=true` lifts role back to 2=registered)
- Provision groups (mapped to `learn_cohorts` with `source='api'`)
- Sync group membership (mapped to `learn_cohort_members`)

The IdP **cannot** modify moderators, admins, or super-admins. Promoting a member past role 2 is a manual action inside Mobieus; SCIM PATCH requests that target a moderator or admin return `404 notFound` from the SCIM surface (without revealing the user exists).

The IdP **cannot** scrape your local-account directory either. SCIM `GET /Users` returns only `scim_managed=1` rows — manually-created tenant accounts never appear in the response.

## Step 1 — Issue a bearer credential

1. Sign in to your tenant as a Tenant Admin
2. Go to **`/admin/learn/scim-credentials`**
3. Click **Issue credential**, give it a descriptive name (e.g. *"Okta production"*) and an optional slug
4. **Copy the token immediately.** It's shown exactly once. The platform stores only the SHA-256 hash; a lost token means revoke + re-issue.

The token format is `ms_scim_<base64url>`. Treat it like any other production secret — store it in your IdP's secret manager, never in source code.

## Step 2 — Connect your IdP

The SCIM base URL is `https://YOUR-TENANT.mobieus.io/scim/v2`.

### Okta

1. **Admin → Applications → Browse App Catalog →** create a **SCIM 2.0 Test App (Bearer Token)** or use your existing Mobieus app
2. **Provisioning → Integration**
   - **SCIM connector base URL:** `https://YOUR-TENANT.mobieus.io/scim/v2`
   - **Unique identifier field for users:** `userName`
   - **Supported provisioning actions:** *Push New Users*, *Push Profile Updates*, *Push Groups*
   - **Authentication mode:** *HTTP Header*
   - **Authorization:** `Bearer ms_scim_…`
3. Click **Test API Credentials**. You should see *"App Profile Settings have been updated successfully."*
4. **To App →** enable *Create Users*, *Update User Attributes*, *Deactivate Users*. Save.

### Microsoft Entra ID (Azure AD)

1. **Enterprise applications →** create or open your Mobieus app
2. **Provisioning → Get started → Provisioning Mode:** *Automatic*
3. **Admin Credentials**
   - **Tenant URL:** `https://YOUR-TENANT.mobieus.io/scim/v2`
   - **Secret Token:** your `ms_scim_…` bearer
4. **Test Connection.** You should see *"The supplied credentials are authorized to enable provisioning."*
5. **Mappings → Provision Microsoft Entra ID Users:** ensure `userPrincipalName → userName`, `mail → emails[type eq "work"].value`, `givenName → name.givenName`, `surname → name.familyName`, `Switch([IsSoftDeleted], , "False", "True", "True", "False") → active`
6. **Settings → Provisioning Status:** *On*. Save.

### Workday

1. **Workday Studio →** add a new SCIM endpoint
2. **Endpoint URL:** `https://YOUR-TENANT.mobieus.io/scim/v2`
3. **Auth:** Bearer token, paste `ms_scim_…`
4. Map your Workday worker fields to SCIM attributes (the same set as the Okta + Entra examples above)
5. Schedule the integration (Workday recommends every 30-60 minutes for SCIM)

### Test the connection from a terminal

Before turning on provisioning, verify the credential works:

```bash
curl -H "Authorization: Bearer ms_scim_..." \
     https://YOUR-TENANT.mobieus.io/scim/v2/ServiceProviderConfig
```

Expected response (200, `application/scim+json`):

```json
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
  "patch":  {"supported": true},
  "bulk":   {"supported": false},
  "filter": {"supported": true, "maxResults": 200},
  ...
}
```

A `401` means the token is wrong, revoked, or the feature flag (`learn_scim`) isn't on for your tenant — check **`/admin/ai`** under the mobieusLearn group.

## Step 3 — Push your first user

Once provisioning is on, your IdP will start pushing users. Verify on Mobieus:

1. **`/admin/learn/scim-credentials → click your credential`**
2. The detail page shows the last 100 audit rows: method, path, status, response time, IP
3. The status histogram (2xx / 4xx / 5xx) lights up green within ~30 seconds of the first push
4. **`/admin/users`** shows the new member with the `SCIM` badge

## Group → cohort mapping

When your IdP creates a SCIM Group, Mobieus creates a row in `learn_cohorts` with:

- `source = 'api'`
- `source_reference = <Group externalId>`
- `name = <displayName>`
- `owner_user_id` = the lowest-id super-admin (role=5) in your tenant

The owner attribution is automatic so the cohorts table's required `owner_user_id` constraint is satisfied. If your tenant has no super-admin, the SCIM Group create call returns `503 unavailable` with the message *"no super-admin to own SCIM-provisioned cohorts"* — create at least one role-5 user before turning on group sync.

## Email verification (anti-hijacking)

SCIM-created users land with `email_verified_at = NULL`. The legitimate owner of the email address still has to go through the regular verification flow before any privileged action. The IdP controls the row but **not** the email's ownership claim.

This is intentional. A malicious or compromised IdP could otherwise pre-claim email addresses that don't belong to it.

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| `404` on `/scim/v2/ServiceProviderConfig` | `learn_scim` flag is off for your tenant | Enable on `/admin/ai` |
| `401 invalid_token` | Wrong, revoked, or disabled credential | Re-issue from `/admin/learn/scim-credentials` |
| `404 notFound` on PATCH a known user | User is not SCIM-managed, or has role > 2 | SCIM only manages its own rows. Promote the user via the Mobieus admin UI, not via SCIM |
| `503 unavailable` on Group create | No super-admin to attribute ownership to | Create a role-5 super-admin user |
| `409 uniqueness` on User create | `externalId` already exists | Pick a different `externalId` or PATCH the existing row |

## Audit retention

Every SCIM request lands in `learn_scim_audit` — method, path, body hash (never the body itself), status, response time, IP. Rows are kept indefinitely. The body hash lets you verify "did the IdP send X" without storing the body content.

The credential detail page shows the last 100 rows; export older history via the public API or by running:

```sql
SELECT * FROM learn_scim_audit
 WHERE credential_id = <id> AND created_at >= NOW() - INTERVAL 30 DAY
 ORDER BY id DESC;
```

## Rotating a credential

1. Issue a new credential on `/admin/learn/scim-credentials`
2. Update your IdP's auth header to the new token
3. Verify a successful sync (the new credential's audit log should start filling in)
4. Revoke the old credential

There's no rolling-key support — Mobieus accepts only the credential whose SHA-256 matches what the IdP sends. Plan the cutover during a quiet provisioning window.

## When to NOT use SCIM

SCIM is overkill for tenants under ~50 members. The manual invite flow on `/admin/users` is faster to set up and easier to debug. SCIM pays off when:

- You're already running an IdP for other apps (Okta, Entra, Workday)
- New hires need access automatically on day one
- Former employees need access cut off immediately
- You want group membership to mirror your IdP's groups in `learn_cohorts`

For a tenant under that threshold, the manual flow is probably the right call.

---

*Tracked under feature key `learn_scim` (Phase 4 M6). Per ADR-0047. Endpoint surface in `/scim/v2/*` per RFC 7643/7644.*