Back to blog

SCIM protocol: how it works, what it solves, and why it matters

Auth & identity

Aug 11, 2025

Author: Stytch Team

SCIM protocol: how it works, what it solves, and why it matters

The System for Cross-domain Identity Management (SCIM) protocol is a standard that large organizations use to manage access and automatically keep their user accounts and groups in sync across multiple platforms. You might be more familiar with terms like "Directory Sync", "User Provisioning", or "Account Provisioning and Management), but these are all powered by SCIM under the hood.

If you've ever had to skip happy hour because HR called you at 5pm on a Friday to tell you a departing engineer’s access needs to be immediately revoked from EVERY. SINGLE. SYSTEM. — and in the next 30 minutes! — you've probably already wished you were using SCIM, because it cascades a single change across all downstream SaaS apps automatically.

Read on to find out more about SCIM: its key features, how the SCIM protocol works behind the scenes, and what it means to be able to say to your customers "Yes, we support SCIM."

What is the SCIM protocol and what is it used for?

The SCIM protocol defines how identity data is to be sent between a SCIM client and a SCIM service provider. The purpose of SCIM is to enable identity management automation — keeping user accounts and the groups they belong to in sync between a SCIM client (in most cases this is an organization's identity provider like Okta or Microsoft Entra ID), and the many downstream SaaS apps (SCIM service providers) that are connected to it.

SCIM specifies which endpoints to send data to, the format of the payload, and the shape of the HTTP requests and responses. It's tightly coupled to the SCIM schema, which defines how that identity data should be structured when sent to a SCIM API. The SCIM schema defines resources like User and Group, each with a series of defined attributes like userName or email.

SCIM handles everything to do with changes to user or group data, and it synchronizes those changes across all your apps. This includes:

  • User provisioning: Creates user accounts across all apps when a new hire joins
  • User deprovisioning: Removes user accounts when someone leaves
  • User synchronization: Keeps user details (like email address or job title) up to date across all apps
  • Group provisioning: Creates groups like "Sales" or "Engineering"
  • Group deprovisioning: Deletes or deactivates groups that are no longer needed
  • Group membership synchronization: Adds or removes users from groups as needed and syncs the digital org chart with all apps

Enterprises need SCIM so their identity providers like Microsoft Entra ID or Okta can automatically provision and deprovision users and groups across their many applications. This makes the work of IT teams easier, eliminates the need for custom scripts to sync identity data, and improves security across their growing toolchains. So, if you're building a SaaS product and want to sell to enterprises, there's a good chance you'll be asked “Do you support SCIM?”

Image showing the flow of data from an identity provider to SaaS apps during SCIM provisioning
Identity providers can use SCIM to provision users and groups with data that originates in the HR system

Some large companies (including Salesforce, Google, and VMware) collaborated under the Open Web Foundation to develop the initial SCIM 1.0 specification as an open standard. The Internet Engineering Task Force (IETF) later standardized the protocol as SCIM 2.0, documented in (RFC 7644) and its core schema (RFC 7643).

The SCIM protocol keeps user account data and group memberships in sync across your services and apps, but it does not decide or enforce what resources a user can access. Instead, it passes identity attributes, such as group memberships or entitlements, to downstream applications, which then apply their own access control rules based on that information.

How does the SCIM protocol work?

For your app to act as a SCIM service provider, you'll need to build and expose a compliant SCIM REST API that supports all required schema operations, versioning, and secure authentication — or delegate this to a managed SCIM provider like Stytch, which delivers these capabilities out of the box.

Then, whenever there's a change to some identity data in a SCIM client (which typically happens when an HR system syncs data with it), the SCIM client sends an HTTP request to the SCIM API of each connected downstream app to create, update, or delete that user or group. The SCIM protocol defines exactly how to make these API requests.

Diagram showing how the SCIM protocol enables a SCIM client (like an identity provider) to talk to a SCIM service provider via a SCIM API

Protocol elements and features required for SCIM implementation

Schemas and resources

SCIM has two core resource types: User and Group. Each of these conform to a schema that defines its structure, such as what fields each resource has and what data types they are. In a managed SCIM implementation like Stytch’s, these schemas are pre-validated for compliance, saving engineering teams from manual RFC checks and schema mapping headaches.

SCIM also defines a standardized extension called enterprise:User, which extends the core User resource with additional attributes such as department and manager. You can think of a schema like a class in object-oriented programming and a resource as the equivalent of an object — it's an instance of the schema that follows its structure.

The SCIM schema specification (RFC-7643) defines some of these fields (such as userName) as required, and some (like emails or title) as optional. Some attributes like emails, roles, and groups are multi-valued arrays, allowing for multiple values to be added (for example, personal email vs. work email). Below is an example of a SCIM User resource.

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "userName": "gandalf",
  "name": {
    "givenName": "Gandalf",
    "familyName": "The Grey"
  },
  "emails": [
    {
      "value": "gandalf@wizards.middleearth",
      "type": "work",
      "primary": true
    }
  ],
  "active": true,
  "title": "Wizard",
  "roles": [
    {
      "value": "Advisor",
      "type": "council"
    }
  ],
  "groups": [
    {
      "value": "fellowship-of-the-ring",
      "display": "Fellowship of the Ring"
    },
    {
      "value": "wizards",
      "display": "Wizards"
    }
  ]
}

And here's an example of a Group resource. Even though the above User resource shows Gandalf as a member of the Fellowship of the Ring group, the same information appears in the Group resource for Fellowship of the Ring. This bidirectional structure allows either resource type to be used to update changes, which allows for more flexible syncing between systems.

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
  "displayName": "Fellowship of the Ring",
  "members": [
    {
      "value": "gandalf",
      "display": "Gandalf"
    },
    {
      "value": "frodo",
      "display": "Frodo Baggins"
    },
    {
      "value": "aragorn",
      "display": "Aragorn"
    },
    {
      "value": "legolas",
      "display": "Legolas"
    },
    {
      "value": "gimli",
      "display": "Gimli"
    },
    {
      "value": "boromir",
      "display": "Boromir"
    },
    {
      "value": "samwise",
      "display": "Samwise Gamgee"
    },
    {
      "value": "merry",
      "display": "Meriadoc Brandybuck"
    },
    {
      "value": "pippin",
      "display": "Peregrin Took"
    }
  ]
}

CRUD operations, HTTP methods and endpoints

SCIM supports CRUD (create, read, update, delete) operations for each resource via the standard POST, GET, PUT, and PATCH HTTP methods. SCIM defines a /Users endpoint for users and a /Groups endpoint for groups, and there's also an extra endpoint called /Bulk for performing operations in bulk.

Below is an example of the /Users SCIM API endpoints that perform different CRUD operations.

  • GET /Users – Lists users
  • GET /Users/{id} – Retrieves a single user
  • POST /Users – Creates a new user
  • PUT /Users/{id} – Replaces a user
  • PATCH /Users/{id} – Partially updates a user
  • DELETE /Users/{id} – Deletes a user

While PUT and PATCH can both be used to update a user, PATCH is most commonly used for partial updates, allowing you to change only specific fields rather than replacing the entire object. Some identity providers, however, continue to use PUT for certain update scenarios. Stytch’s SCIM API supports both methods, ensuring compatibility with a wide range of identity provider behaviors while still encouraging efficient PATCH-based updates.

To understand what SCIM operations look like in practice, consider what happens when user Gandalf is promoted: his surname changes from The Grey to The White, his title changes from Wizard to Chief Wizard (White Council), and he's added to the group White Council. Once these fields have been updated in the identity provider, the identity provider sends a PATCH request to the /Users endpoint of each connected SCIM API, with his new title and group, updating only the changed fields. The PATCH request looks like this:

{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    {
      "op": "replace",
      "path": "name.familyName",
      "value": "The White"
    },
    {
      "op": "replace",
      "path": "title",
      "value": "Chief Wizard (White Council)"
    },
    {
      "op": "add",
      "path": "groups",
      "value": [
        {
          "value": "white-council",
          "display": "White Council"
        }
      ]
    }
  ]
}

HTTP status codes

Like any REST API, SCIM uses the standard HTTP status codes (like 200 OK, 201 Created, 400 Bad Request, or 500 Internal Server Error). However the SCIM protocol specification defines when to use each status code and provides example error messages.

Security and authentication

All SCIM protocol requests must be served over TLS (HTTPS). No specific authentication method is mandated, but common authentication methods include OAuth 2.0 bearer tokens or API keys.

OAuth is the best authentication method for enterprises, as it supports fine-grained access control (via scopes) and delegated authorization. If you're using OAuth, the access tokens must be time-limited and validated on the server side on every request. You'll also need to include access scope checks. For example, if a token has the following scopes:

"scopes": ["read:users", "read:groups"]

Then a request like PATCH /Users/gandalf with that token should get rejected, since it only has read access.

As well as scopes, you should also validate the issuer (iss) and audience (aud) values in the OAuth token. The issuer tells you who issued the token (which is usually the identity provider) and the audience specifies who (or which system) the token is for — in this case, the SCIM API.

If you're marketing to enterprises, you'll likely have a multi-tenant setup, so you'll need to ensure that authentication is scoped per tenant (to stop them from being able to access each other's data).

Finally, although it's not in the SCIM specification, many enterprises prefer that user or group deletions be implemented as soft deletes. That is, when they delete something, it's marked as deleted rather than completely removed from the database. This allows them to change their minds and easily restore accounts that they accidentally deleted.

Shared schemas for interoperability

SCIM's shared core schemas for users and groups means that all systems speak the same language, from the identity provider to each SCIM service provider.

Defined resource types

The User and Group resource types map to real organizational needs, which makes it easy to manage access control for individual users and groups.

Querying capabilities

SCIM supports querying out of the box, which is useful for supporting admin dashboards or when a new SCIM service provider is being added and an initial sync needs to take place. In this situation, querying can help you check which users already exist.

Filtering is a common example of querying:

GET /Users?filter=userName eq "Gandalf"
GET /Users?filter=groups.display eq "Fellowship of the Ring"

Pagination is useful when you have a very large number of users and want to deal with them in chunks. For example, to return the first 50 users, you could query:

GET /Users?startIndex=1&count=50

And to return the next 50 users (page 2), you could query:

GET /Users?startIndex=51&count=50

The SCIM protocol also specifies how to sort data, but this only works if it's supported by the SCIM service provider. Most SCIM service providers support sorting for some common attributes, but not all of them. If you want to be a SCIM service provider, you should implement sorting on any attributes your users are likely to need, like userName, familyName, a group's displayName, and the date resources that were created or lastModified. Below is an example of how to sort by userName:

GET /Users?sortBy=userName&sortOrder=ascending

Self-service administration and visibility

Enterprises often want SCIM’s querying, filtering, and sorting capabilities surfaced in an interface that non-technical teams can use. This makes it possible for IT admins to configure integrations, view the current sync status, and troubleshoot issues without opening tickets with engineering.

For example,Stytch’s Admin Portal includes a <AdminPortalSCIM> component that lets authorized organization members create and configure SCIM connections, rotate bearer tokens, and manage group-to-role mappings for automated RBAC assignments. It’s part of an embeddable UI via Stytch’s frontend SDKs and embeds directly into your application with full styling control, giving your enterprise customers secure, self-service management of SCIM workflows.

Bulk operations support for scalability

The /Bulk endpoint allows for the mass creation, updating, or deletion of multiple users or groups on one API call. This is ideal for mass onboarding, offboarding, and HR system synchronizations.

Concurrency-safe updates with versioning and ETags

ETags are HTTP headers that identify the version of a resource during an update, and meta.version is a field inside the SCIM resource's JSON that contains the same version string, which is typically a hash. They are both used to manage concurrency and stop one update from overriding another.

Common SCIM implementation challenges

While the SCIM protocol is standardized, its correct and secure implementation in a production environment can be tricky. Some of the challenges engineers face are:

  • Idempotency: This means that making the same API call multiple times has the exact same effect as making it once, even if something went wrong during the first request. For example, if our earlier PATCH request to give the Gandalf user membership of a new group "White Council" timed out, we wouldn't want the second version of the request to add a duplicate group, or cause any duplicate logs or emails.
  • Identity providers' lack of consistency: While the SCIM protocol does allow for schema extensions (such as adding custom attributes like department, manager or costCenter, not all identity providers handle them in the same way, meaning you'll need to build custom mapping logic for each identity provider.
  • Bulk sync reliability: SCIM does have bulk operations via /Bulk, but large syncs can hit rate limits or partially fail, so you'll need to add retries, or write logic to handle backoff or partial successes.
  • Managing concurrency and race conditions: SCIM is typically used in multi-system environments where multiple updates can happen at the same time. This can sometimes cause race conditions where one update silently overrides another, or data becomes inconsistent across systems. To avoid this, you'll need to use ETag-based version control and transactional updates wherever possible.

These issues are manageable, but they take time, design, and ongoing maintenance, which is why many teams opt to use a managed SCIM provider. For most companies, SCIM isn’t a differentiator for their product. It’s critical plumbing that has to work flawlessly but doesn’t create direct customer value. That’s why building it in-house often isn’t worth the ongoing cost compared to using a provider that specializes in it.

With Stytch, complexities from idempotency handling to multi-IdP schema mapping are addressed by default, allowing teams to integrate SCIM in days rather than months.

SCIM vs LDAP: Competitors or complementary?

SCIM and LDAP are both protocols for managing identity data, but they're used in different contexts and can be used together.

While SCIM is used to push identity data from an identity provider to downstream SaaS apps, LDAP is used to pull (query) data from a directory service, such as Microsoft Active Directory into an identity provider. LDAP can also modify entries in a directory service.

Many organizations have an on-premises user directory that is the single source of truth about user data. They have this for historical or security reasons, and they use LDAP to sync this with other systems like an identity provider.

SCIM vs SAML: Why you probably need both

SCIM and SAML aren't competitors — they tend to be used together to handle different parts of user access. SAML handles the authentication side of things and is used to implement single sign on, whereas SCIM is more about provisioning users and groups. As both authentication and provisioning are needed, the two are ideal to be used together.

While it is possible to use one without the other, you'll need an alternative for whichever one you're not using. You could choose to use SAML with OIDC, for example, or SCIM with a custom provisioning script. However, for enterprises, SAML and SCIM are the best fit.

Avoiding SCIM implementation complexity by using Stytch

Even though the SCIM protocol is standardized, implementing your own custom SCIM connector in house is slow, error prone, and complex. Your SCIM API needs to support the storing and maintaining of users and groups, tracking whenever attributes change, and handle things like reactivating accounts after soft deletes.

You also need to handle idempotency issues, as identity providers like to retry requests automatically. Your system must be able to safely handle repeated requests without causing duplicate or corrupted data. Filtering, pagination, and sorting, which are not trivial to implement, must also be developed from scratch and maintained.

Engineering teams can instead choose a managed SCIM solution like Stytch. Stytch has already solved these problems for you, and it is maintained by SCIM specialists who keep it secure and up to date with the latest SCIM specification updates.

Here's how Stytch works for a standard example: deprovisioning a user.

Once a user is deprovisioned in the organization's identity provider, Stytch receives a SCIM request with details of this change. Stytch then marks the user as deactivated (soft deleting them so they can be restored in case of accidental deletion), revokes all their sessions, and triggers a webhook to your application notifying it of any changes, and your application is then responsible for updating its internal model of that user.

A workflow of how Stytch uses the SCIM protocol to deprovision a user.

The same reliable pattern applies to provisioning new users, updating attributes like job titles, and managing group membership changes; giving you a single, consistent workflow for every stage of the identity lifecycle.

For any change to a user or group, your application needs to record that change, as well as handle logic about who is allowed to access what; for example, you could decide that only those in the group Software Engineers have access to GitHub integrations. Stytch helps with the synchronization of any changes to all downstream apps.

Stytch supports enterprise readiness through features like OAuth and ETag support, and it makes it easy to scale with native support for pagination, filtering, bulk syncs, and backoff. You also get support for SAML and LDAP alongside SCIM in the same unified authentication platform, giving you everything you need for organization-wide SSO and identity management automation in one place.
Give SCIM a try with Stytch or reach out if you have more questions.

Share this article