Legal AI infrastructure for firms
AI RFP discovery and response drafting
Automatic.coBusiness process automation
Secure AI virtual data rooms
Custom SCIM Provisioning Development for Okta and Microsoft Entra ID
Custom SCIM provisioning is the gate between selling to a mid-market ops lead and selling to an enterprise identity team. Build a compliant SCIM 2.0 endpoint and the IT buyer stops writing manual user audits; skip it and the deal stalls at procurement.
The specs are specific and the vendors are opinionated. Okta and Microsoft Entra ID both implement SCIM 2.0, but each reads your endpoint differently, and the places they diverge are where most integrations break.
What SCIM 2.0 Expects From Your Endpoint
SCIM 2.0 is the IETF's RFC 7644 protocol for pushing identity data between systems, published in September 2015 and still the baseline every major IdP speaks. A compliant endpoint exposes a fixed set of resources, authenticates the IdP, and returns responses in a specific JSON shape.
A service provider endpoint needs, at minimum:
- /Users with GET, POST, PATCH, PUT, DELETE
- /Groups with GET, POST, PATCH, PUT, DELETE
- /Schemas with GET
- /ResourceTypes with GET
- /ServiceProviderConfig with GET
Microsoft's own Entra ID SCIM API reference lists the same five, with GET, POST, PATCH, and DELETE under the Graph base URL. That matters because your endpoint is the mirror image of what Entra publishes: whatever Microsoft returns from its own SCIM surface, your app has to accept.
Authentication is almost always an OAuth 2.0 bearer token. Filtering (?filter=userName eq "[email protected]") and pagination (startIndex, count) are required on list endpoints. Skip either and conformance tests fail silently.
Building for Okta's Install Base
Okta's footprint is the practical reason to support it first. The company reported over 20,000 customers and more than 7,000 OIN integrations as of January 31, 2026, with 5,100 of those paying more than $100,000 in annual contract value. That is where your SaaS needs to appear if you sell to IT-led buying committees.
Two Okta-specific quirks catch builders:
- Attribute mapping is UI-first. Okta admins remap any SCIM attribute inside the admin console before syncing, so your endpoint has to accept whatever subset of the schema the admin chooses to send, not assume every field is populated.
- Group push semantics. Okta pushes memberships as PATCH operations on the Group resource, not the User resource. Your /Groups/{id} PATCH handler has to resolve add, replace, and remove ops on the members array in the exact order received.
Private SCIM integrations, the non-OIN apps your customers add themselves, also need URL-safe tenant routing so each Okta tenant maps to its own namespace. That is where your multi-tenant isolation story pays off: one Okta tenant per logical workspace, one bearer token, no cross-tenant lookups in the hot path.
Where Microsoft Entra ID Diverges
Entra ID runs SCIM sync on a scheduled cycle, roughly every 40 minutes, with per-app throttling at 10,000 requests per 10 minutes and a tenant-wide ceiling of 130,000 requests per 10 minutes. If your failure rate exceeds 40%, the job drops to once a day; four weeks past that, Entra disables the sync entirely. Design accordingly: idempotent handlers, meaningful 2xx and 4xx responses, no 500s on soft errors.
Entra also sends operations differently from Okta:
- PATCH over PUT. Entra prefers sparse PATCH for updates. The parser needs the full op grammar from RFC 7644, including add, replace, and remove with JSON Pointer-style paths and filter expressions like emails[type eq "work"].value.
- Soft delete by default. Entra's default is to set active: false on a PATCH rather than issue a DELETE. Treat active: false as the deprovisioning signal unless the admin explicitly configures hard delete.
- Stable externalIds. Entra can push groups, but it expects stable externalId values on both users and groups. Rotate those at your peril.

Schema Mapping Without Over-Engineering
The core SCIM schemas (User, EnterpriseUser, Group) cover most of what enterprise buyers ask for. Resist the urge to invent custom schemas on day one. Extend the EnterpriseUser schema for the fields that already have canonical names (employeeNumber, department, manager, costCenter) and add a custom schema extension only when a buyer's contract requires a field with no existing mapping.
A reasonable first-release scope:
- Core User attributes: userName, name.givenName, name.familyName, emails, active
- EnterpriseUser: employeeNumber, department, manager
- Group: displayName, members
- One custom extension namespace reserved for licenses or role bindings
That is enough to pass Okta's SCIM conformance checks and Entra's provisioning validator without carrying dead fields through every migration. Treat it as the same boundary work you would scope on any other API integration: the schema is the contract, and every field you add is one more thing procurement will want tested.
Deprovisioning Decides the Procurement Audit
The SCIM feature enterprise security teams genuinely care about is deprovisioning. A 2025 analysis found that 53% of SaaS breaches involved orphaned accounts that should have been deprovisioned, and 89% of enterprise CISOs now rank orphaned accounts among their top three SaaS governance issues.
What that means for the build:
- Deprovisioning has to be a terminal state with an audit trail. Record the SCIM event ID, the IdP tenant, the timestamp, and the user resource as last seen.
- Revoke OAuth refresh tokens and active sessions in the same transaction as the SCIM PATCH. A user marked active: false who still has a valid session is the exact condition breach reports describe.
- Return 200 or 204 only after dependent cleanup. Returning 200 before sessions are revoked sets up a non-reproducible production incident.
The same discipline applies to the first 90 days with a new vendor. The audit a buyer runs in week four is usually a terminated-user test, not a full pen test.
When to Build SCIM In-House
A production-ready SCIM endpoint for one IdP, with CI conformance tests and one gallery listing, is typically six to ten engineering weeks for a team that already knows the identity domain and has a stable user model. A second IdP is roughly half of that, assuming the schema mapping layer was designed to be IdP-agnostic from the start. Budget against the same reality as any other enterprise integration scope: the long tail is retries, idempotency, and conformance edges, not the happy path.
Choose custom SCIM when you sell into enterprises whose security teams require certified provisioning, you can staff the engineers who will own the integration for its life, and the user model is stable enough that schema drift will not force quarterly rework. Pick an off-the-shelf SCIM gateway (WorkOS, Frontegg, or similar) when you need to clear one procurement gate this quarter and the margin can absorb the per-tenant fee. Build it in-house when both IdPs, both tenancy models, and the deprovisioning audit trail matter more than shipping speed.
