SCIM setup — Okta
Okta is a Certified vendor. The integration is listed in the Okta Integration Network (OIN) once the submission package (§8 pre-GA) is approved.
Prereqs
- MOD tenant on a plan with
scim_enabled = true(Enterprise tier). - Okta admin access.
- A SCIM bearer token created in MOD Dashboard → Admin → SCIM tab (it's shown once at creation — copy it then).
Steps
1. Configure the connector
In Okta:
- Applications → Browse App Catalog → search "MOD" (once OIN listed) OR Applications → Create App Integration → SAML 2.0 + SCIM.
- Provisioning tab → Configure API Integration.
- Set the SCIM connector endpoint to:
https://api.modtechlabs.com/scim/v2
- Bearer Token: paste the plaintext from MOD's "Create token" modal.
- Click Test API Credentials.
- Expected: "MOD SCIM provisioning was verified successfully."
2. Map attributes
Default mapping is sufficient for v1:
| Okta attribute | MOD attribute | notes |
|---|---|---|
| userName | userName | usually email |
| name.givenName | name.givenName | |
| name.familyName | name.familyName | |
| profileUrl | (ignored) | not stored |
| emails[type=work].value | MOD treats this as the primary email | |
| externalId | externalId | opaque |
If using tenantRole (custom extension):
- Add a custom attribute under your Okta directory schema:
mod_tenant_role(string). - In MOD Dashboard → Admin → SCIM mapping, map your Okta group → the MOD permission template.
- Setting
mod_tenant_roledirectly via PUT/PATCH is an alternative to group-driven role assignment.
3. Enable provisioning
- Provisioning tab → To App.
- Enable: Create Users, Update User Attributes, Deactivate Users.
- Save.
4. Assign users + groups
- Assignments tab → assign individual users or groups.
- Expected (for users): MOD receives
POST /scim/v2/Usersfor each. New users appear in Dashboard → Users. - Expected (for groups): MOD receives
POST /scim/v2/Groups+PATCH .../Groups/{id}for each membership change.
5. Verify in MOD
- Dashboard → Admin → SCIM → Activity tab.
- Filter to "Last hour" + status_class "success" → you should see a trail of 201s and 200s matching what Okta sent.
- Failed assignments appear in the Failed (grouped) sub-tab
grouped by
(external_id, error_detail).
6. Test deactivation
- In Okta, unassign a user from the integration.
- Expected in MOD:
PATCH /Users/{id}withactive=falsethenDELETE /Users/{id}within ~30 seconds. - MOD soft-deletes (status = INACTIVE, deleted_at stamped).
- The 5-min reconcile sweep disables the Keycloak user. The next login attempt by that user returns "Account disabled."
Known Okta-specific behaviours
See the vendor compat matrix for the full list. Highlights:
- Full-replacement PUT on Groups — Okta sends the full members[] on every push. MOD handles it by recomputing roles for the affected set (the union of the old and new members). No tuning needed.
- 5xx retry storm — Okta retries on 5xx every 30s for 24h. MOD's idempotency cache prevents duplicate users.
- Per-app license enforcement — Okta's "Assign" action triggers provisioning. If MOD's seat limit denies, Okta marks the assignment as "Pending push" and retries hourly until the limit is raised.
Troubleshooting
| symptom | likely cause | fix |
|---|---|---|
| "Failed: 401 Unauthorized" | Token revoked or rotated | Generate a fresh token; paste into Okta |
| "Failed: 402 Payment Required" | Plan downgraded; SCIM disabled | Upgrade plan to Enterprise tier |
| "Failed: 429 Too Many Requests" | Burst rate-limit hit | Wait per Retry-After; lower Okta's batch size |
| "Failed: 409 Conflict on POST" | Email belongs to another tenant on MOD | Contact MOD support (no leak by design) |
| "Failed: 400 invalidValue tenantRole" | Mapping page hasn't been configured yet | Dashboard → Admin → SCIM Mapping; pick role |
Screenshots
See CORE/docs-site/docs/assets/scim-okta-*.png (see the Phase E
§7.3 CI check below).