Skip to main content

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:

fieldmeaning
vendorOkta / Azure AD / Google Workspace / JumpCloud / OneLogin
quirkOne-line description of the divergence
vendor_docsURL to the vendor's own documentation
workaroundHow we handle it in CORE/API/scim/
code_linkFile:line where the workaround lives
discovered_dateYYYY-MM-DD when we found this
tiercertified / 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

vendorquirkvendor_docsworkaroundcode_linkdiscovered_datetier
OktaSends members as full replacement on every PUThttps://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 recomputerouters/scim_v2.py:replace_group2026-06-05verified
OktaRetries POST /Users on 5xx every 30s for 24hhttps://help.okta.com/oie/en-us/Content/Topics/users-groups-profiles/usgp-app-provisioning.htmIdempotency cache (7d TTL) returns same response for duplicate requestscim/idempotency.py2026-06-05verified
Azure ADPATCH 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 Nonerouters/scim_v2.py:_apply_partial2026-06-05verified
Azure ADSends externalId as a UUID, not the upstream HR idhttps://learn.microsoft.com/en-us/entra/identity/app-provisioning/customize-application-attributesTreat as opaque — store unchanged in users.external_idrouters/scim_v2.py:_apply_upsert2026-06-05verified
Google WorkspaceDoesn't send Groups via SCIM (uses Directory API)https://support.google.com/a/answer/15531858Group sync via post-GA add-scim-google-directory-api change(none yet)2026-06-05community
JumpCloudEmail lower-cased before send, even if upstream is mixed-casehttps://jumpcloud.com/support/scim-integrationsWe never re-canonicalise on read — what the IdP sends is what we storerouters/scim_v2.py:_apply_upsert2026-06-05community
OneLoginactive=false PATCH leaves group memberships intact (per SCIM spec, deactivation ≠ deletion)https://developers.onelogin.com/scimWe honor the spec — soft-delete (DELETE) drops memberships; PATCH active=false doesn'trouters/scim_v2.py:patch_user2026-06-05community

Process

When you discover a new quirk:

  1. Add a row to the matrix above.
  2. Add the workaround under CORE/API/scim/ with a comment pointing back to this doc.
  3. If it's a Certified / Verified vendor, add a regression case to CORE/API/tests/scim_vendor_smoke/.
  4. 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):