# SCIM vs JIT provisioning: when to use each

**SCIM vs JIT provisioning: when should I use each?**

Use JIT (just-in-time) provisioning for low-friction, first-login onboarding, and use SCIM when you need attribute updates, day-one pre-provisioning, or automated deprovisioning — and expect most teams to eventually run both. JIT provisioning creates a user account on the user's first [single sign-on](https://clerk.com/glossary.md#single-sign-on-sso) (SSO) login by reading attributes from the identity provider's assertion; it is almost free to add but cannot create accounts before first login or remove access when someone leaves. SCIM is a standard protocol (SCIM 2.0, defined by [RFC 7643 and RFC 7644](https://www.rfc-editor.org/rfc/rfc7644)) that lets the [identity provider](https://clerk.com/glossary.md#identity-provider-sso-idp-sso) (IdP) create, update, and deactivate accounts across the full user lifecycle, independent of any login — which is what makes automated offboarding possible.

The two are not really competitors; they solve different stages of the same problem. The IETF's own SCIM requirements document frames provisioning as happening "in a separate context from authentication (aka just-in-time provisioning)" ([RFC 7642](https://www.rfc-editor.org/rfc/rfc7642)). This guide explains how each mechanism works, the deprovisioning gap that drives the decision, a balanced framework of factors to weigh for your own situation, the implementation gotchas that bite teams in production, and how authentication providers — including Clerk — support both.

## Why user provisioning is a decision worth getting right

Provisioning is the plumbing behind every enterprise login, and the cost of getting it wrong almost always shows up at offboarding, not onboarding. Before comparing the two mechanisms, it helps to see the full problem they are trying to solve.

### The identity lifecycle: joiners, movers, and leavers (JML)

User provisioning is not a single event — it spans an employee's entire relationship with an organization. Identity teams model this as joiners, movers, and leavers (JML): a joiner needs an account and the right access on day one, a mover needs access adjusted when their role or team changes, and a leaver needs access removed the moment they depart ([Netwrix](https://netwrix.com/en/cybersecurity-glossary/security-concepts/joiner-mover-leaver-jml/); [StrongDM](https://www.strongdm.com/blog/joiners-movers-and-leavers)). Any provisioning approach that only handles the joiner is solving half the problem.

### The hidden cost of manual provisioning

Manual account creation and removal does not scale, and its worst failure mode is invisible. Hand-managed accounts drift away from the directory that is supposed to be the source of truth, and the riskiest gap is offboarding: a departed employee who keeps working access is both a security incident waiting to happen and a compliance finding waiting to be written up.

The security case for automating deprovisioning rests on a simple fact — standing access that outlives its need is exactly what attackers reuse — rather than on any single headline statistic. The data backs the priority up. The IBM Cost of a Data Breach 2025 report put the global average breach at $4.44 million ([IBM](https://www.ibm.com/reports/data-breach)). The way breaches begin is shifting: in Verizon's 2025 Data Breach Investigations Report (DBIR), stolen credentials were the single most common initial-access vector at 22%, but in the 2026 edition vulnerability exploitation overtook them as the number-one entry point at 31%, and credential abuse as the _initial_ vector fell to 13% ([Verizon DBIR](https://www.verizon.com/business/resources/reports/dbir/)). Credentials still matter enormously to how breaches _succeed_, though: credential abuse appears in 39% of breaches across the full attack chain (DBIR 2026), and 88% of basic web-application attacks involved stolen credentials (DBIR 2025). An account that is never deprovisioned is precisely the kind of standing credential that keeps showing up later in the chain.

Identity incidents are common, and ex-employee access is a measurable part of the problem. Half of organizations (50%) reported an identity-based security incident in the prior 12 months ([GuidePoint/Ponemon State of IAM Maturity 2025](https://www.guidepointsecurity.com/resources/the-state-of-iam_maturity_2025/)). A 2023 DoControl survey found that 31% of companies had former employees access SaaS assets after leaving ([via Security Magazine](https://www.securitymagazine.com/articles/99004-thirty-one-percent-of-former-employees-still-have-company-saas-access)), and an older OneLogin survey (2017) found 20% of organizations had suffered a breach tied to failing to deprovision an ex-employee, with 48% aware that former employees still retained access to corporate apps ([OneLogin](https://www.onelogin.com/blog/deprovisioning-secret)). These vendor and survey figures vary in rigor, but they all point the same direction: the leaver is where manual provisioning hurts.

### Where this decision shows up

This choice surfaces in three common settings: B2B SaaS products selling to other organizations, internal enterprise tools used by a company's own workforce, and web apps adopting enterprise SSO for the first time. If your application accepts logins from a customer's identity provider — or will soon — you will eventually have to decide how accounts get created and, more importantly, how they get removed.

## What is JIT provisioning?

JIT provisioning is account creation that happens at login time, as a side effect of single sign-on. It is the cheapest way to get accounts into your app, and its limits all stem from the fact that nothing happens unless someone logs in.

### How JIT provisioning works

JIT provisioning is triggered by the first successful SSO authentication — most commonly [SAML](https://clerk.com/glossary.md#security-assertion-markup-language-saml), and in some implementations [OIDC](https://clerk.com/glossary.md#openid-connect). When a new user authenticates, your application reads the identity attributes from the assertion or ID token (the email from the SAML `NameID` or the OIDC `sub` plus claims, along with name and any mapped fields), creates the user record on demand, and logs the person in — all in one pass ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/jit-provisioning.md); [Okta](https://developer.okta.com/docs/concepts/scim/)). There is no separate setup step for the administrator and no account in your database until that moment.

### What JIT provisioning does — and does not — handle

JIT handles account creation on first login and, in many (but not all) implementations, refreshes attributes on subsequent logins. Whether attributes re-sync on every login is application-specific — some apps update the record each time, others create it once and never touch it again — so never assume a single universal rule.

What JIT cannot do is the rest of the lifecycle. It cannot pre-provision: there is no account until the user logs in, so you cannot grant day-one access or @mention someone before they have ever signed in. And it cannot deprovision: when an administrator removes a user in the IdP, no login occurs, so no signal ever reaches your app. Clerk's own JIT documentation routes deprovisioning needs to [Directory Sync](https://clerk.com/glossary.md#directory-sync) (SCIM) for exactly this reason.

### Strengths and limitations of JIT

The strengths are real: minimal engineering effort, no extra endpoint to build or operate, and the fastest possible path to "works with our customer's SSO." For an early-stage product landing its first SSO-using customer, JIT is often all you need.

The limitations are the mirror image. JIT is login-dependent, so a terminated employee whose IdP login is blocked never triggers any "JIT deprovision" — their existing account and any live session simply persist until the session expires on its own ([OpenIAM](https://www.openiam.com/workforce-identity-concepts/access-management/what-is-just-in-time-provisioning)). It offers no day-one access, and it leaves orphaned accounts behind when people leave. Those orphaned accounts still carry valid credentials and usually go unmonitored ([Trustle](https://www.trustle.com/post/orphaned-accounts)).

## What is SCIM provisioning?

SCIM is a standard protocol for pushing the full account lifecycle from an identity provider into your application, without waiting for a login. Where JIT reacts, SCIM is proactive.

### How SCIM provisioning works (the SCIM 2.0 protocol)

SCIM stands for System for Cross-domain Identity Management. SCIM 2.0 is a REST-and-JSON standard defined by two IETF documents published in 2015: [RFC 7643](https://www.rfc-editor.org/rfc/rfc7643) (the core schema for `User` and `Group` resources) and [RFC 7644](https://www.rfc-editor.org/rfc/rfc7644) (the protocol). Both carry the status "Proposed Standard."

In a SCIM integration, the identity provider is the source of truth and your application is the "target" that receives changes. The IdP pushes lifecycle events to your application's SCIM endpoint as standard HTTP operations — `POST`, `GET`, `PUT`, `PATCH`, and occasionally `DELETE` — on `/Users` and `/Groups` collections, with a few read-only discovery routes (`/ServiceProviderConfig`, `/ResourceTypes`, `/Schemas`). Every request is authenticated with a [bearer token](https://clerk.com/glossary.md#bearer-token) over TLS ([Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups); [Okta](https://developer.okta.com/docs/concepts/scim/)). Because the IdP drives it, none of this depends on the user ever signing in.

### The full identity lifecycle: create, update, deprovision

SCIM covers every JML stage in one protocol: it provisions accounts, updates attributes when they change in the directory, syncs group membership, and deactivates accounts — all without a login event. Crucially, it supports pre-provisioning, so a user can be granted access (and appear in your app's user list, ready to be @mentioned or assigned) weeks before their first sign-in ([WorkOS](https://workos.com/blog/scim-impact-b2b-saas-scalability)). Role and team changes propagate immediately, instead of waiting for the user to log out and back in.

### Why deprovisioning is the core value of SCIM

The asymmetry is the whole point: onboarding is a convenience, but reliable offboarding is what justifies the protocol. When a user is removed or disabled in the IdP, SCIM tells your application to mark the account inactive — typically a `PATCH` that sets the `active` attribute to `false` — at which point a well-built application ends the user's sessions and revokes access, closing the gap that JIT leaves wide open ([WorkOS](https://workos.com/blog/how-scim-deprovisioning-works)).

One nuance matters for accuracy: RFC 7643 says the meaning of `active` is "determined by the service provider," so the protocol does not itself guarantee that sessions are revoked — your application (or your auth vendor) implements that behavior. Treat instant session revocation on deprovision as a feature to verify, not a given.

### Strengths and limitations of SCIM

SCIM's strengths are everything JIT lacks: full lifecycle automation, real deprovisioning, pre-provisioning, group and role sync, and a directory that stays continuously in sync. Its limitations are operational. You have to build and operate a SCIM endpoint, every IdP has its own quirks, and there are simply more moving parts to maintain — which is what makes the gotchas and the build-versus-buy question (both below) worth taking seriously.

## SCIM vs JIT provisioning: the key differences

The two mechanisms differ on what triggers them, what they can create or remove, and how much they cost to run. The table below summarizes the contrast; the prose after it explains the differences that actually drive the decision.

| Dimension                         | JIT provisioning                                   | SCIM provisioning                                       |
| --------------------------------- | -------------------------------------------------- | ------------------------------------------------------- |
| Trigger                           | User's first SSO login                             | IdP pushes lifecycle events (no login needed)           |
| Protocol basis                    | A login-time pattern on SAML/OIDC (not a standard) | SCIM 2.0 standard (RFC 7643/7644)                       |
| Account creation                  | On first login only                                | Any time, including before first login                  |
| Attribute updates                 | Sometimes, on later logins (app-dependent)         | Yes, pushed on change                                   |
| Pre-provisioning (day-one access) | No                                                 | Yes                                                     |
| Deprovisioning / offboarding      | No (access lingers until session expiry)           | Yes (deactivate with `active: false` + revoke sessions) |
| Group / role sync                 | Brittle (assertion claims, exact-string match)     | Yes (`/Groups`, group-to-role mapping)                  |
| Implementation effort             | Low (rides on existing SSO)                        | Higher (build and operate a SCIM endpoint per IdP)      |
| Typical use stage                 | Early / first SSO support                          | Enterprise readiness, compliance, scale                 |

Read the table top to bottom and a pattern emerges: JIT is a feature of the login, while SCIM is a feature of the directory. That single distinction explains the three differences that matter most.

### The deprovisioning gap

The most important difference is also the simplest: JIT cannot remove access, and SCIM can. This is the hinge the entire "when to use each" decision turns on. With JIT alone, blocking a user in the IdP stops _new_ logins but does nothing to the account, data, permissions, or active sessions that already exist in your app. With SCIM, the IdP's removal flows through to your app and ends access.

> If reliable offboarding is a requirement — for security, for compliance, or because a customer demands it — JIT alone is not enough. SCIM (or an equivalent provider-managed deprovisioning mechanism) is what closes the gap.

### Pre-provisioning vs first-login provisioning

SCIM can create an account before the user ever logs in, so access and group membership are ready on day one. JIT cannot: the account does not exist until the first successful sign-in. If your product needs people to be invited, assigned to teams, or @mentioned before they have authenticated, that is a SCIM capability.

### Implementation and maintenance effort

JIT is close to free once you already support SSO — it reuses the login handler and adds no new endpoints. SCIM is a larger, ongoing commitment: a service endpoint to build, per-IdP behavior to accommodate, and load and idempotency concerns to handle over time. That cost difference is real and is the reason many teams reach for a provider that supplies SCIM for them rather than building it.

## Clearing up a common confusion: SCIM vs SAML (and where JIT fits)

The most common misconception in this area is conflating "can no longer authenticate" with "the account no longer exists." A team ships SAML SSO with JIT, an employee leaves, the IdP blocks their login — and everyone assumes the account is gone. It is not. The account, its data, its permissions, and any live session all persist, because SAML is stateless: it proves identity at the moment of login and never tells your application that a user was later removed ([RFC 7642](https://www.rfc-editor.org/rfc/rfc7642)).

Two related myths follow from the same root. The first is that SCIM and SAML are interchangeable; the second is that SCIM requires SAML. Both are false. They are independent protocols that solve different problems, and SCIM can run over an OIDC connection just as well as a SAML one ([WorkOS](https://workos.com/blog/scim-vs-saml)).

> A clean mental model: SAML and OIDC are **authentication** — they decide who is allowed to sign in. SSO is the experience built on top of them. SCIM is **provisioning** — it decides which accounts exist and keeps them in sync. JIT is provisioning that rides on the login event, which is exactly why it gets mistaken for SAML itself.

Put another way: SSO decides who can sign in; SCIM decides who should exist. You need both to fully manage enterprise identity, and confusing the two is how the deprovisioning gap goes unnoticed until an auditor or a security questionnaire finds it.

## When to use each: a balanced decision framework

There is no universal winner. The right choice depends on how you weigh the factors below for your own application, customers, and stage. Treat them as independent levers, not a ranking — team size matters for some products and barely registers for others.

### Factor 1 — Do you need automated deprovisioning?

This is the factor that most often forces the decision. If reliable, automatic offboarding matters — if you cannot accept a departed user keeping access until a session happens to expire — then SCIM (or a provider-managed equivalent) is effectively required, because JIT cannot deprovision at all. If your offboarding is genuinely handled some other way (for example, very short session lifetimes plus a manual removal process you trust), JIT may be acceptable for now.

### Factor 2 — Security and compliance requirements

Automated, provable access removal is a recurring theme across the major security frameworks, even though none of them name SCIM specifically. NIST SP 800-53 Rev. 5 control AC-2 (Account Management) and its enhancement AC-2(1) (Automated System Account Management) call for creating, disabling, and removing accounts in step with personnel changes ([NIST](https://csrc.nist.gov/pubs/sp/800/53/r5/upd1/final)). ISO/IEC 27001:2022 covers the same ground in Annex A controls A.5.16 (Identity management) and A.5.18 (Access rights) ([ISMS.online](https://www.isms.online/iso-27001/annex-a-2022/5-16-identity-management-2022/)). [SOC 2](https://clerk.com/glossary.md#soc-2)'s Trust Services Criteria CC6.2 and CC6.3 require that credentials and access be removed when access is no longer authorized ([AICPA](https://www.aicpa-cima.com/resources/download/2017-trust-services-criteria-with-revised-points-of-focus-2022)). If you operate in a regulated industry or sell into one, these requirements push hard toward SCIM, because automated deprovisioning is far easier to evidence than a manual checklist.

### Factor 3 — Customer size and enterprise procurement

SCIM frequently becomes a hard procurement requirement for larger customers and can block a deal outright. Automated deprovisioning is one of the most-tested items in enterprise security reviews, and many SaaS products gate SCIM behind an enterprise edition or a minimum seat count (for instance, some vendors document SCIM access only above a seat threshold — point-in-time, and worth verifying for any specific product). Practitioners often cite a rule of thumb that SCIM turns into a hard requirement around the time you land your first roughly 1,000-seat customer ([CIAM Compass](https://guptadeepak.com/ciam-compass/guides/scim-provisioning/); [Hashorn](https://hashorn.com/blog/enterprise-ready-saas-sso-scim-audit-logs)). Treat that number as a heuristic from individual practitioners, not measured data — but treat the underlying pressure as real.

### Factor 4 — Integration and engineering complexity

Weigh the cost of building and operating a SCIM endpoint against JIT's near-zero cost. Building SCIM in-house is a handful of routes on paper, but the real work is per-IdP behavior, idempotency, large-tenant load, and ongoing maintenance (covered in the gotchas below). A key question here is whether your authentication provider supplies SCIM for you — if it does, much of this factor disappears, which is the heart of the build-versus-buy decision.

### Factor 5 — Provisioning timing (day-one access vs first login)

If users must have access before they ever log in — common when people are added to projects, mentioned, or assigned work ahead of their start — SCIM's pre-provisioning is the only option. If first-login account creation is acceptable for your product, JIT is enough on this axis.

### Why most teams end up using both

In practice the common pattern is to ship JIT first for convenience, then add SCIM when the lifecycle, deprovisioning, or enterprise need arrives. There is a genuine tension in _when_ to add it: some practitioners advise waiting until a customer actually asks ([Hashorn](https://hashorn.com/blog/enterprise-ready-saas-sso-scim-audit-logs)), while others recommend adding it proactively, before your first large deal, so it never becomes a blocker ([CIAM Compass](https://guptadeepak.com/ciam-compass/guides/scim-provisioning/)). Both are reasonable rules of thumb; the right call depends on your sales motion and risk tolerance.

### Quick-reference scenarios

A few concrete starting points, drawn from the factors above:

- If you are an early-stage SaaS landing your first SSO customer, JIT is usually enough for now.
- If you are closing your first enterprise deal and SCIM is on the security questionnaire, add SCIM.
- If you sell into a regulated industry, plan for SCIM from the start.
- If offboarding and large-tenant lifecycle management are your pain, SCIM is the answer; JIT cannot help.

## Implementation considerations and common gotchas

The conceptual difference is clean. The implementations are where the surprises live. This section covers what each side actually requires and the production gotchas worth planning for.

### Implementing JIT provisioning

JIT implementation is mostly [attribute mapping](https://clerk.com/glossary.md#attribute-mapping). You read identity from the assertion and create or update the record. Two practices save pain later: match users on a stable identifier such as the SAML `NameID` or OIDC `sub` rather than on email (emails change), and decide deliberately whether to re-sync attributes on every login or only at creation.

Role mapping via the assertion is the brittle part. It relies on exact-string matching of group names, and identity providers complicate it — Microsoft Entra sends group object IDs (GUIDs), not human-readable names, and group claims in a token are capped at 150 for SAML assertions and 200 for [JWT](https://clerk.com/glossary.md#json-web-token), with anything beyond the cap causing the group claims to be omitted entirely ([Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-fed-group-claims)). That last detail is a silent failure: past the limit, roles do not just truncate, they disappear.

### Implementing SCIM provisioning

A SCIM service provider exposes a small set of routes, secures them with a bearer token, and is configured into each IdP. The endpoint count is smaller than folklore suggests — a minimal users-only implementation is around five routes, and a full users-plus-groups-plus-discovery implementation is closer to fifteen, not the "sixteen endpoints" sometimes quoted. The skeleton below shows the core in TypeScript; note that the deprovisioning path is the `active: false` branch of `PATCH`, not `DELETE`.

```typescript
import express, { type Request, type Response, type NextFunction } from 'express'

const scim = express.Router()
scim.use(express.json({ type: ['application/json', 'application/scim+json'] }))

// Every SCIM route is bearer-authenticated over TLS.
scim.use((req: Request, res: Response, next: NextFunction) => {
  const token = req.header('authorization')?.replace('Bearer ', '')
  if (token !== process.env.SCIM_BEARER_TOKEN) {
    return res
      .status(401)
      .json({ schemas: ['urn:ietf:params:scim:api:messages:2.0:Error'], status: '401' })
  }
  next()
})

// Provision a user — the IdP can call this before the user ever logs in.
scim.post('/Users', async (req: Request, res: Response) => {
  const user = await createUser(req.body) // map emails, userName, name, externalId
  res.status(201).json(toScimUser(user))
})

// Existence and idempotency checks: GET /Users?filter=userName eq "jane@acme.com"
scim.get('/Users', async (req: Request, res: Response) => {
  const results = await findUsers(req.query.filter as string | undefined)
  res.json(toListResponse(results))
})

scim.get('/Users/:id', async (req: Request, res: Response) => {
  const user = await getUser(req.params.id)
  return user ? res.json(toScimUser(user)) : res.sendStatus(404)
})

// Deactivation (active -> false) arrives in different shapes by IdP — Okta sends
// no path (value is the object { active: false }); Entra sends path "active"
// (boolean false only with the aadOptscim062020 compliance flag; the string
// "False" without it). op casing varies too (Entra: "Replace"), so compare
// case-insensitively. This per-IdP variation is what makes PATCH the buggiest op.
function deactivates(ops: Array<{ op: string; path?: string; value: unknown }>): boolean {
  const isFalse = (v: unknown) =>
    v === false || (typeof v === 'string' && v.toLowerCase() === 'false')
  return ops.some((o) => {
    if (o.op?.toLowerCase() !== 'replace') return false
    if (o.path === 'active') return isFalse(o.value) // Entra: path-based
    const v = o.value as Record<string, unknown> | null // Okta: no path
    return !o.path && typeof v === 'object' && v !== null && isFalse(v.active)
  })
}

// The lifecycle workhorse. A single PATCH can change attributes AND set
// active=false, so apply every operation first, then revoke sessions as a side
// effect of deactivation — never skip ops, and never DELETE.
scim.patch('/Users/:id', async (req: Request, res: Response) => {
  const ops = req.body.Operations as Array<{ op: string; path?: string; value: unknown }>

  await applyPatch(req.params.id, ops) // persists all changes, including active
  if (deactivates(ops)) {
    await revokeSessions(req.params.id) // active=false must also end live sessions
  }

  res.json(toScimUser(await getUser(req.params.id)))
})

export default scim
```

Two routes round out the set but are used less often: `PUT /Users/:id` (full replace) and `DELETE /Users/:id` (rarely exercised, because most IdPs deactivate rather than delete). The same verbs apply to `/Groups`, plus the three read-only discovery routes. The contrast with JIT is the headline: JIT adds _zero_ new routes — it reuses the SSO login handler — while SCIM is a service you own. And `PATCH` is consistently the most bug-prone operation, because its exact shape differs by IdP — Okta and Microsoft Entra even encode the same `active: false` deactivation differently ([Okta](https://developer.okta.com/docs/api/openapi/okta-scim/guides/scim-20); [Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups)).

### SCIM gotchas to plan for

Most SCIM pain comes from per-IdP differences, even though everyone claims SCIM 2.0 compliance — a situation one IAM vendor calls "premature standardization" ([Evolveum](https://docs.evolveum.com/iam/iga/identity-provisioning/scim-troubles/)). The gotchas worth planning for:

- **Push timing varies, so the "SCIM experience" depends on the IdP.** Okta pushes changes in an event-driven way — it is notified when a user is created, assigned, changed, or deprovisioned, and acts on it near-immediately (not on a poll) ([Okta](https://developer.okta.com/docs/concepts/scim/)). Microsoft Entra, by contrast, provisions on a fixed background cycle that runs approximately every 40 minutes and is not configurable, though an admin can force a single user through sooner with on-demand provisioning (typically under 30 seconds) ([Microsoft Entra: use-scim](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups); [known issues](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/known-issues); [provision on demand](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/provision-on-demand)). Deprovisioning latency, therefore, is an IdP property, not something your app controls.
- **Not every directory is an equally capable SCIM source.** Okta and Microsoft Entra push the full SCIM 2.0 lifecycle — users _and_ groups — to any endpoint you expose, but Google Workspace's automated provisioning is narrower: it provisions users, not groups. Google Groups can only scope _which_ users are provisioned; the groups themselves are never created or synced in the target app, so there is no automatic group provisioning ([Google Workspace](https://knowledge.workspace.google.com/admin/users/advanced/about-automated-user-provisioning); [Keeper](https://docs.keeper.io/en/sso-connect-cloud/identity-provider-setup/g-suite-keeper/google-workspace-user-provisioning-with-scim)). If your customers standardize on Google Workspace, plan for a users-only directory-sync story rather than the group sync Okta or Entra provide.
- **Deprovisioning is deactivation, not deletion.** Okta sends `active: false` and never issues a `DELETE`; Entra disables first and only hard-deletes after a soft-delete window; GitHub suspends enterprise users rather than deleting them ([Okta](https://developer.okta.com/docs/concepts/scim/); [GitHub](https://docs.github.com/en/enterprise-cloud@latest/admin/managing-iam/provisioning-user-accounts-with-scim/deprovisioning-and-reinstating-users)). Build your endpoint around deactivation as the normal case.
- **Microsoft Entra's default SCIM payloads aren't RFC-compliant — a flag fixes it.** By default Entra sends the `active` attribute as the JSON string `"False"` (not the boolean `false`), capitalizes the operation name (`Replace`), and structures some multi-attribute and group-removal `PATCH` operations in non-standard ways. Appending the `aadOptscim062020` flag to the SCIM Tenant URL switches Entra to RFC 7644-compliant payloads. As of early 2026 it is still opt-in — Microsoft has long said the compliant behavior "will become the default," but it hasn't — so either set the flag or make your endpoint tolerant of both shapes (the skeleton above already is: it lower-cases `op` and accepts a string or boolean `active`) ([Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/application-provisioning-config-problem-scim-compatibility)).
- **Nested groups do not survive cleanly.** Entra provisions only the direct members of an assigned group and "can't read or provision users in nested groups"; Okta flattens nested Active Directory groups into the parent on import ([Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/how-provisioning-works); [Okta](https://support.okta.com/help/s/article/How-does-Okta-handle-nested-groups)). Expect flattened membership, or have admins assign the leaf groups directly.
- **Large-tenant initial sync is a load event.** Onboarding a big customer can fire thousands of near-concurrent `POST` requests, which can exhaust connection pools and trigger N+1 database patterns ([DEV Community](https://dev.to/grunet/operational-challenges-for-scim-servers-176a)). A robust endpoint returns HTTP `429 Too Many Requests` with a `Retry-After` header so the IdP backs off — Okta honors this, pausing the task and using exponential backoff, and reads only integer-seconds `Retry-After` values ([Okta](https://developer.okta.com/docs/concepts/scim/)). Worth knowing: `429` is not defined by SCIM itself (RFC 7644 §3.12 does not list it; it comes from [RFC 6585](https://www.rfc-editor.org/rfc/rfc6585)), so treat it as standard HTTP back-pressure layered on top of SCIM.
- **A cloud IdP can only push to an endpoint it can reach.** SCIM is server-to-server: the IdP sends provisioning requests _into_ your SCIM endpoint, so that endpoint must be reachable from the IdP. For a public SaaS that is automatic, but an internal tool with no public ingress cannot be reached by a cloud IdP directly — the team running the IdP has to deploy an outbound provisioning agent inside the network (such as the [Okta Provisioning Agent](https://help.okta.com/oie/en-us/content/topics/provisioning/opp/opp-architecture.htm) or [Microsoft Entra's on-premises provisioning agent](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/on-premises-application-provisioning-architecture)), which connects outbound so no inbound firewall ports are opened. JIT sidesteps this entirely, because the SAML assertion or OIDC token travels through the user's browser at sign-in rather than over a direct IdP-to-app connection.
- **Ordering and idempotency.** A group can reference a user before that user's `POST` has landed, producing a transient `404`; use `externalId` as the stable key to make retries idempotent ([Stytch](https://stytch.com/blog/scim-protocol-explained/)).

### How JIT and SCIM coexist (and when to turn JIT off)

When SCIM owns the lifecycle, leaving JIT on can create conflicting or duplicate records, or let a login overwrite attributes that SCIM is supposed to manage. That is why teams often disable JIT once SCIM is authoritative — but which side wins is a platform configuration choice, not a protocol rule. Docker defaults to JIT overwriting SCIM ([Docker](https://docs.docker.com/enterprise/security/provisioning/scim/provision-scim/)), whereas data.world automatically disables JIT when SCIM is enabled ([data.world](https://docs.data.world/en/344825-jit-vs-scim-provisioning--what-is-the-difference-and-why-it-matters-.html)). The dedup contract that keeps the two from colliding is a stable shared identifier: `externalId` on the SCIM side matched to the `NameID` or `sub` on the login side.

### Build vs. buy

Building SCIM in-house looks like a handful of endpoints, but the cost is in the long tail: per-IdP quirks (with `PATCH` the buggiest operation), idempotency, large-tenant load, and continuous maintenance as IdPs change. Effort estimates range from roughly 4–8 weeks for a single-IdP MVP (a practitioner estimate from [Hashorn](https://hashorn.com/blog/enterprise-ready-saas-sso-scim-audit-logs)) up to several months for a hardened, multi-IdP implementation (per [WorkOS's](https://workos.com/blog/why-building-scim-is-hard) vendor ROI modeling). Both are interested estimates, not neutral benchmarks — but the direction is consistent.

Observability is an underrated part of this decision. When an in-house endpoint silently fails to provision a user, your team often cannot see _why_, because the IdP's own provisioning logs live on the IdP side — Microsoft Entra's "provisioning logs" and Okta's "System Log" — and the receiving application "[doesn't] have access to these logs" ([WorkOS](https://workos.com/guide/implementation-challenges-of-a-homegrown-scim-solution), a vendor source; [Microsoft Entra provisioning logs](https://learn.microsoft.com/en-us/entra/identity/monitoring-health/concept-provisioning-logs)). Triage then degrades into a back-and-forth with the customer's IT admin. A managed provider supplies the missing application-side view — for example, Clerk's "Directory users" tab shows each provisioned user's status and last sync time ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/directory-sync.md)). For many teams, that operational support — not just the endpoints — is the real argument for letting an identity provider handle provisioning.

## How authentication providers handle provisioning

Most teams do not build provisioning from scratch; they get it from their authentication or identity platform. Here is how that landscape looks, and where Clerk fits.

### The vendor landscape (a fair, balanced survey)

First, a direction check that prevents a lot of confusion: the workforce identity providers your customers operate (Okta, Microsoft Entra ID, OneLogin) _push_ provisioning outward, while the authentication platforms you embed in your app _receive_ it. When you shop for "a SCIM solution," you are shopping for the receiving side.

On that receiving side, mature B2B and CIAM platforms commonly support both JIT and SCIM, with quality and coverage varying by product. WorkOS, Auth0, Frontegg, Stytch, SSOJet, Scalekit, PropelAuth, and Descope all offer SCIM-based directory sync alongside SSO, and several add self-service admin portals so your customers can configure their own connections. Across the industry, SCIM and directory sync tend to sit on higher or enterprise tiers rather than free entry plans — a durable pattern worth budgeting for, though specific tiers and prices change often and should be verified against each vendor's current pricing. The point of this section is capability, not a price comparison: the meaningful differences between providers are SCIM scope (users only versus users and groups), deprovisioning immediacy, group-to-role mapping, and whether a hosted admin portal is included.

### Provisioning with Clerk

Clerk supports both approaches, which maps cleanly onto the framework above: JIT for first-login onboarding and Directory Sync (SCIM) for the full lifecycle, plus a lighter OIDC-based middle option. Pricing and feature details below are current as of June 2026 and are point-in-time — verify them against Clerk's pricing page before you commit.

#### JIT provisioning during SAML SSO

Clerk creates an account on a user's first SAML SSO sign-in, reading the identity from the assertion, and can keep user data current on subsequent sign-ins via a "Sync user attributes during Sign in" toggle. This is documented for Clerk's SAML connections — Microsoft Entra ID (Azure AD), Google Workspace, Okta Workforce, and custom SAML — and is the SAML-side counterpart to the SCIM lifecycle ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/jit-provisioning.md)).

#### Directory Sync (SCIM) for the full lifecycle

Clerk's Directory Sync (SCIM) is generally available and enabled for all users. It provides automated provisioning, deprovisioning with immediate session revocation, attribute syncing, and group syncing. When a user is removed or deactivated in the IdP, Clerk deactivates the corresponding Clerk user and immediately revokes all of their active sessions — so deprovisioning is enforced at once, not on a delay ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/directory-sync.md)). Custom attribute mapping and group-to-role mapping are also generally available (the rollout completed in May 2026), with custom attributes mapped into the user's [`publicMetadata`](https://clerk.com/docs/guides/users/extending.md) and role mapping enabled by default ([Clerk changelog](https://clerk.com/changelog/2026-05-21-directory-sync-groups-attributes-ga.md)). Documented SCIM identity providers are Okta and Microsoft Entra ID, and Directory Sync is configured per enterprise connection.

#### A third tier: EASIE

Between JIT and full SCIM, Clerk offers EASIE — an OIDC-based enterprise SSO option for Google Workspace and Microsoft Entra ID. EASIE includes automatic deprovisioning by re-checking, at session-token issuance, whether the user is still active in the OpenID provider, with up to a roughly 10-minute worst-case delay ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/overview.md)). It is a middle ground — lighter than SCIM, but with real deprovisioning that JIT lacks — and it is not a standard provisioning protocol, so it does not replace SCIM where the full lifecycle or broader IdP support is needed.

#### Example configuration

Setup is concept-first and stays in the dashboard: you enable Directory Sync on an existing enterprise connection, Clerk generates an Endpoint URL (the SCIM base URL) and a bearer token, and you paste both into your IdP's provisioning configuration. Because Directory Sync requires an existing SAML or OIDC enterprise connection, there is no standalone SCIM-only setup — it builds on a connection you already have.

#### Fair caveats and requirements

A few honest constraints. Directory Sync requires an existing enterprise connection and is not standalone, so it complements your choice rather than removing it. SCIM provisioning and deprovisioning are included with the enterprise connection (there is no separate Directory Sync line item on Clerk's pricing page), but enterprise connections themselves are a paid, metered feature: one is included on the Pro plan, with additional connections metered on a sliding scale ([Clerk pricing](https://clerk.com/pricing)). Group-to-role mapping additionally requires linking the connection to an organization and using custom roles — capabilities packaged in Clerk's [Enhanced B2B Authentication add-on](https://clerk.com/docs/guides/organizations/control-access/role-sets.md) — so the mapping feature is GA and enabled by default, but the org-link-plus-custom-roles prerequisite is a paid boundary (pricing is point-in-time and packaging can change — verify at Clerk's pricing page). Finally, a concrete requirement that catches teams off guard: Clerk requires an email in the SCIM `emails` attribute for every provisioned user and will not fall back to `userName`, so a SCIM payload that omits an email fails to provision that user ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/directory-sync.md)). Clerk does not document a specific merge or dedup behavior for pre-existing JIT users when SCIM is later enabled on the same connection, so do not assume automatic reconciliation; on the sign-in path, Clerk does auto-link accounts by verified email ([Clerk](https://clerk.com/docs/guides/configure/auth-strategies/enterprise-connections/account-linking.md)).

## Conclusion: choosing the right provisioning approach

The decision rule is short: use JIT for low-friction first-login onboarding, and use SCIM when you need attribute updates, day-one pre-provisioning, or automated deprovisioning. Because they cover different stages of the same lifecycle, most teams end up running both — shipping JIT first for speed, then adding SCIM as the lifecycle, compliance, or enterprise need arrives. The deprovisioning gap is the factor that most often forces the move to SCIM, but the right weighting of deprovisioning, compliance, customer size, engineering cost, and timing is yours to make for your own product.

Whichever way you lean, you do not have to build it alone. Authentication providers — Clerk among them — support both JIT and SCIM, so you can start with first-login provisioning and turn on the full directory-synced lifecycle when your customers ask for it, without re-architecting your auth.

## Frequently asked questions

## FAQ

### What is JIT provisioning?

Just-in-time (JIT) provisioning creates a user's account automatically the first time they sign in through single sign-on. The application reads identity attributes — typically email and name — from the identity provider's SAML assertion or OIDC token and creates the record on demand, so no account exists until that first login.

### What is SCIM provisioning?

SCIM (System for Cross-domain Identity Management) provisioning is a standard protocol that lets an identity provider create, update, and deactivate accounts in your application across the full user lifecycle, independent of login. SCIM 2.0 is defined by RFC 7643 and RFC 7644 (2015) and works over REST and JSON.

### What is the difference between SCIM and JIT provisioning?

The difference is the trigger and the lifecycle coverage. JIT only reacts to a login and can create or refresh an account, but it cannot pre-provision accounts before first login or deprovision them when a user leaves. SCIM is pushed by the identity provider on any change and covers the whole lifecycle, including automated deprovisioning.

### How does SCIM provisioning work?

Your application exposes a SCIM 2.0 endpoint — REST routes under `/Users` and `/Groups` — secured with a bearer token over TLS. The identity provider sends `POST`, `PATCH`, `PUT`, and occasionally `DELETE` requests to that endpoint as users are created, changed, or deactivated in the directory, so your app stays in sync without waiting for a login.

### Is SCIM the same as SAML or SSO?

No. SAML and OIDC are authentication protocols that decide who is allowed to sign in, and SSO is the experience built on top of them. SCIM is a separate provisioning protocol that decides which accounts exist and keeps them in sync. They are independent: SCIM does not require SAML, and SAML does not provision or deprovision accounts on its own.

### Does JIT provisioning handle deprovisioning?

No. JIT only runs at login, so when an employee is removed from the identity provider there is no login event to react to and no signal reaches your app. The account, its data, and any active session persist until the session expires. Closing that gap is the main reason teams add SCIM.

### Can you use SCIM and JIT together?

Yes, and many teams do — JIT for convenient first-login onboarding and SCIM for the full lifecycle. Because both can create accounts, teams often disable JIT once SCIM is authoritative to avoid duplicate or conflicting records, but which side wins is platform-specific, so check your provider's behavior.

### When should a SaaS app add SCIM?

Add SCIM when the lifecycle matters more than first-login convenience: when you need reliable automated deprovisioning, day-one access before first login, or when an enterprise customer makes it a procurement requirement. Practitioners often cite adding it around the first large (roughly 1,000-seat) customer, but that is a heuristic, not a hard number.

### Is SCIM required for enterprise customers?

Increasingly, yes — SCIM and automated deprovisioning are common items in enterprise security questionnaires, and many products gate SCIM to an enterprise edition or a minimum seat count. It is not universal, but for larger buyers it is frequently a hard requirement that can stall or block a deal.

### What is SCIM 2.0?

SCIM 2.0 is the current version of the standard, published by the IETF in 2015 as RFC 7643 (the core schema for users and groups) and RFC 7644 (the protocol). Both are Proposed Standards and define the REST/JSON operations and the `User`, `Group`, and `active` attributes that provisioning relies on.

### What happens to a user when they are deprovisioned via SCIM?

In most implementations the identity provider sends a `PATCH` that sets the user's `active` attribute to `false`. The application marks the account inactive and, in a good implementation, revokes the user's active sessions so access ends immediately. The exact effect of `active: false` is defined by the application, not mandated by the spec.

### Does deprovisioning delete the user?

Usually not. Most identity providers and applications deactivate the account (`active: false`) rather than hard-deleting it, so data is retained for audit. Okta never sends a `DELETE` for deprovisioning, and GitHub suspends rather than deletes enterprise users; Microsoft Entra only issues a hard delete after a soft-delete window.

### Does Clerk support SCIM and JIT provisioning?

Yes. Clerk supports JIT provisioning on SAML SSO connections and Directory Sync (SCIM) for the full lifecycle, with immediate session revocation on deprovision. SCIM provisioning is included with an enterprise connection, and Clerk also offers EASIE — an OIDC-based option for Google Workspace and Microsoft Entra ID with lighter automatic deprovisioning.

### What is the difference between SCIM and "SAML JIT" provisioning?

"SAML JIT" is just JIT provisioning riding on a SAML login — an account is created from the SAML assertion at first sign-in. SCIM is the separate provisioning protocol that runs independently of login and adds the attribute updates and deprovisioning that SAML JIT cannot do on its own.
