System for Cross-domain Identity Management
- New to Ory? Talk to the team about features and plans.
- Already a customer? Open a support ticket.
SCIM (System for Cross-domain Identity Management) is a standard for automating the exchange of user identity information between identity domains or IT systems. It is designed to simplify the management of user identities in cloud-based applications and services. SCIM provides a common schema for representing user identities and a RESTful API for managing them. This allows organizations to automate the provisioning and de-provisioning of user accounts across multiple systems, reducing administrative burden and improving security.
In Ory Network, SCIM is available at the organization level. This means that within one project, you can have multiple organizations with different SCIM configurations. Each organization can have one or more SCIM clients, each with its own endpoint URL, authentication secret, and data mapping. This allows organizations to tailor their SCIM implementation to meet their specific needs and requirements.
Identities provisioned through the SCIM API are automatically created in Ory Network and added to that SCIM client's organization. The provisioned identities can then log in through any of the organization's configured SSO methods.
For the full endpoint reference — request and response shapes, pagination, filtering, and error responses — see the SCIM API reference.
How SCIM relates to organizations
SCIM in Ory Network is always scoped to an organization:
- Each SCIM client belongs to exactly one organization. The organization is fixed when you create the client and determines where provisioned identities are placed.
- An identity belongs to at most one organization. An identity can be a member of a single organization or of none, but never of two organizations at the same time.
Because of this, what happens when a SCIM client provisions a user (POST /Users) depends on whether a matching identity already
exists, and which organization it belongs to:
| Situation | Result |
|---|---|
| No matching identity exists | A new identity is created in the SCIM client's organization. |
| A matching identity exists in the same organization | The existing identity is updated using the client's data mapping. |
| A matching identity exists with no organization, and a verified email domain matches | The identity is linked into the organization and provisioning continues (see Auto-linking). |
| A matching identity exists in a different organization | Provisioning fails with a 409 Conflict error (see Cross-organization conflicts). |
Auto-linking
When a SCIM client provisions a user that collides with an existing identity, Ory Network tries to link the SCIM record to that identity instead of creating a duplicate. A collision is detected by checking, in order:
- The login identifier (the identity's credentials identifier, typically derived from
userName). - A verified email address.
- A recovery address.
There is no matching on externalId.
When a collision is found:
- If the existing identity is already a member of the SCIM client's organization, it is updated through the data mapping.
- If the existing identity belongs to no organization, and it has a verified email whose domain matches one of the organization's verified domains, the identity is linked into the organization and provisioning continues. This is useful when a user signed up (or was provisioned by SSO) before the organization started using SCIM.
- Otherwise — including when the existing identity belongs to a different organization — provisioning fails with a conflict.
Cross-organization conflicts
Because an identity can only belong to one organization, provisioning a user who already exists in a different organization
fails with a 409 Conflict:
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "409",
"scimType": "uniqueness",
"detail": "Could not create user: identity already exists in another scope"
}
To resolve this, either delete the existing identity, or move it into the target organization, before retrying provisioning. See the API reference for the full error model.
Set up identity provisioning with SCIM
To set up identity provisioning with SCIM, follow these steps:
Create an organization
If you haven't already, create an organization. This organization will be used to manage your SCIM settings and provision identities.
Configure a SCIM client
In the organization view, under SCIM clients, click Add SCIM client. This will open a form where you can configure your SCIM client's settings.
- Client ID: Enter an identifier for your SCIM client. This identifier is part of the base URL that the client uses to access the Ory Network SCIM server, so it should be unique within your project.
- Label: Enter a human-readable label for your SCIM client.
- Authorization header secret: Enter a secret in the client authentication's secret field. Clients authenticate by sending
this secret in the
Authorizationheader of their requests. See Authentication for the exact header format. - Data mapping: When the client creates or updates a user, the supplied data is applied to the identity based on this data mapping. See Data mapping below.
Once the client is created, the Console shows its SCIM server URL. Configure your identity provider to send SCIM requests to that URL, using the authorization header secret as its token.
Data mapping
The data mapping is a Jsonnet script that defines how the data the SCIM client sends is mapped to the
identity in Ory Network. This mapping is applied any time the SCIM client creates or updates a user (POST, PATCH, or PUT),
and the identity is updated accordingly.
The mapping is unidirectional: it only runs when the SCIM client writes data. If an identity trait is later changed elsewhere
(for example by the user or another SSO method), the SCIM client cannot read the updated value back. On read (GET), the SCIM
attributes are returned from the data stored at provisioning time, not re-derived from the identity.
Relationship to the OIDC and SAML Jsonnet mapper
The SCIM data mapping uses the same Jsonnet engine and the same output schema as the OIDC and SAML SSO data mapping. The differences are:
- It is configured per SCIM client (each client has its own mapper), not per SSO provider.
- The input is the SCIM payload in
std.extVar('scim')instead of OIDCclaimsor SAML attributes. - It additionally receives the existing identity in
std.extVar('identity')(see below).
The script must return a JSON object as defined in the Jsonnet reference — identity.traits,
identity.metadata_public, identity.metadata_admin, and identity.verified_addresses. For the available SCIM input
attributes, see the user resource schema.
Preserving data with the identity variable
The mapper also receives the existing identity (if one exists) through the std.extVar('identity') variable, alongside the
scim variable. It exposes traits, metadata_public, and metadata_admin, each defaulting to an empty object when unset.
This matters because the mapping uses full-replace semantics: the object your script returns overwrites the corresponding
identity fields. If you map metadata_public without merging the existing values back in, any metadata that SCIM does not manage
(for example an oid set by SAML or OIDC SSO) is lost on the next sync. To preserve it, merge the existing value:
local scim = std.extVar('scim');
local identity = std.extVar('identity');
local existingPublic = std.get(identity, 'metadata_public', {});
{
identity: {
traits: {
email: scim.userName,
},
// Keep metadata SCIM does not manage (for example values set by OIDC/SAML SSO),
// and override only what SCIM should manage.
metadata_public: existingPublic + {
// Add or override only what SCIM should manage here.
},
},
}
A few attributes are applied directly and are not controlled by the mapping: active sets whether the identity can log in, the
organization is taken from the SCIM client's configuration, and password (if present) is stored as a password credential.
On multi-region Ory Network projects, provisioned identities (and their SCIM data) are stored in the same region as the identity.
In addition to the standard mapper output, the mapper may set the region by returning an optional
identity.region field; if it doesn't, the organization's default region is used. An invalid region value causes provisioning to
fail with a 400 error.
Deprovisioning identities
There are two distinct ways to remove access, with different effects:
- Deactivate: set
activetofalse(for example throughPATCH /Users/{id}). The identity is kept but cannot log in. This is reversible — setactiveback totrueto restore access. - Delete:
DELETE /Users/{id}permanently deletes the underlying Ory identity and returns204 No Content. This cannot be undone.
Most identity providers map a user being unassigned or disabled to a deactivation rather than a deletion. Check your provider's configuration to confirm which behavior it uses.
Use the SCIM client
Once you have configured a SCIM client, you can use it to provision identities. The Ory Network SCIM server exposes endpoints for managing users and groups, service-discovery endpoints, pagination, and filtering — all documented in the SCIM API reference.
Refer to these guides for setting up SCIM with specific identity providers:
📄️ API reference
This page is a reference for the Ory Network SCIM server API. It describes the base URL and authentication, every available
📄️ Provision from MS Entra
This page guides you through setting up SCIM provisioning from Microsoft Entra to Ory Network.
📄️ Provision from Okta
This page guides you through setting up SCIM provisioning from Okta to Ory Network. Also refer to the
📄️ Provision from Google Workspace
This page guides you through setting up SCIM provisioning from Google Workspace to Ory Network. Also refer to the Google Workspace
Events
Ory Network emits events for SCIM operations that modify data. They surface in the Ory Console under Activity > Logs & Events, and can be used for auditing, automation, or integration with other systems.
| SCIM action | Events emitted | Description |
|---|---|---|
POST /Users | IdentityCreated | A new identity is provisioned. If the user is auto-linked to an existing identity instead, IdentityUpdated is emitted. |
PUT /Users/{id} | IdentityUpdated | An identity is replaced. |
PATCH /Users/{id} | IdentityUpdated | An identity is partially updated. |
DELETE /Users/{id} | IdentityDeleted | An identity is deleted. |
POST /Groups | SCIMGroupCreated | A new group is created. |
PUT /Groups/{id} | SCIMGroupUpdated (+ IdentityUpdated) | A group is replaced. See the note below about member events. |
PATCH /Groups/{id} | SCIMGroupUpdated (+ IdentityUpdated) | A group is partially updated. See the note below about member events. |
DELETE /Groups/{id} | SCIMGroupDeleted (+ IdentityUpdated) | A group is deleted. See the note below about member events. |
The IdentityUpdated events on group operations are only emitted when the client's data mapping derives identity
data from group membership. In that case, an IdentityUpdated event is emitted for each affected member whose mapped data
actually changes — the members added to or removed from the group (for PUT and PATCH), or all former members (for DELETE).
If the mapping does not use group membership, group operations emit only the group event.
In addition, a SCIMProvisioningError event is emitted whenever a request fails. This is the SCIM provisioning error entry
under Activity > Logs & Events that the provider guides point to for troubleshooting; it carries
the failing request's status code and details.
Event attributes
| Event | Attribute | Description |
|---|---|---|
| All events | SCIMClient | The ID of the SCIM client that made the request. |
IdentityCreated, IdentityUpdated | IdentityActive | Whether the identity is active (true or false). |
| Group events | SCIMGroupID, SCIMGroupExternalID, SCIMGroupDisplayName | Identify the group. SCIMGroupUpdated also includes SCIMGroupAddedIdentityIDs and SCIMGroupRemovedIdentityIDs. |
SCIMProvisioningError | SCIMErrorStatusCode, SCIMErrorStatusText, SCIMErrorDetail | Describe the failure. |
Limitations
The SCIM server advertises its capabilities through GET /ServiceProviderConfig. Notable limitations to be aware of:
- Filtering supports only the
eqoperator, and only on a small set of indexed attributes. See Filtering. - Sorting, ETag/versioning, bulk operations, and a
/Meendpoint are not supported. See Supported features.
