SCIM vendor compatibility matrix
Living document. Every vendor quirk that an integration uncovers gets a row here so future engineers don't have to rediscover them.
How to read
Each row is one quirk — a behaviour that diverges from RFC 7643/7644 or that requires a configuration choice unique to a specific IdP.
Columns:
| field | meaning |
|---|---|
| vendor | Okta / Azure AD / Google Workspace / JumpCloud / OneLogin |
| quirk | One-line description of the divergence |
| vendor_docs | URL to the vendor's own documentation |
| workaround | How we handle it in CORE/API/scim/ |
| code_link | File:line where the workaround lives |
| discovered_date | YYYY-MM-DD when we found this |
| tier | certified / verified / community |
Tiers:
- certified — Vendor-listed integration (OIN / Azure AD app gallery). We run the vendor smoke suite nightly against staging.
- verified — End-to-end tested with a real tenant. No formal listing.
- community — Reported by a customer, partial coverage.
Matrix
| vendor | quirk | vendor_docs | workaround | code_link | discovered_date | tier |
|---|---|---|---|---|---|---|
| Okta | Sends members as full replacement on every PUT | https://developer.okta.com/docs/reference/scim/scim-20/ | replace_group handles full-replacement by recomputing the affected set (union of old + new members) for role recompute | routers/scim_v2.py:replace_group | 2026-06-05 | verified |
| Okta | Retries POST /Users on 5xx every 30s for 24h | https://help.okta.com/oie/en-us/Content/Topics/users-groups-profiles/usgp-app-provisioning.htm | Idempotency cache (7d TTL) returns same response for duplicate request | scim/idempotency.py | 2026-06-05 | verified |
| Azure AD | PATCH uses top-level replace with dict value (no path) | https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups | _apply_partial mutates every recognised key when path is None | routers/scim_v2.py:_apply_partial | 2026-06-05 | verified |
| Azure AD | Sends externalId as a UUID, not the upstream HR id | https://learn.microsoft.com/en-us/entra/identity/app-provisioning/customize-application-attributes | Treat as opaque — store unchanged in users.external_id | routers/scim_v2.py:_apply_upsert | 2026-06-05 | verified |
| Google Workspace | Doesn't send Groups via SCIM (uses Directory API) | https://support.google.com/a/answer/15531858 | Group sync via post-GA add-scim-google-directory-api change | (none yet) | 2026-06-05 | community |
| JumpCloud | Email lower-cased before send, even if upstream is mixed-case | https://jumpcloud.com/support/scim-integrations | We never re-canonicalise on read — what the IdP sends is what we store | routers/scim_v2.py:_apply_upsert | 2026-06-05 | community |
| OneLogin | active=false PATCH leaves group memberships intact (per SCIM spec, deactivation ≠ deletion) | https://developers.onelogin.com/scim | We honor the spec — soft-delete (DELETE) drops memberships; PATCH active=false doesn't | routers/scim_v2.py:patch_user | 2026-06-05 | community |
Process
When you discover a new quirk:
- Add a row to the matrix above.
- Add the workaround under
CORE/API/scim/with a comment pointing back to this doc. - If it's a Certified / Verified vendor, add a regression case to
CORE/API/tests/scim_vendor_smoke/. - If the workaround changed test expectations for an existing vendor, mention it in the commit message.
Vendor-specific config guides
The setup guides are separate docs (one per vendor):