Skip to content
AuthMantraPraxis
authmantra.com ↗Start free trial

ProvisioningEngineering

SCIM 2.0 in plain English

AuthMantra Team5 min readPractical

Short version: headings, key sentences, diagrams and callouts.
SCIM: HR changes flow to appsPATCHHRsystemAuthMantraSCIMApp AApp B
a SCIM PATCHSimulated output
$ PATCH /scim/v2/Users/8f2a
{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"active","value":false}]}
✓ 200 OK, user inactive

SCIM stands for System for Cross-domain Identity Management. Strip away the name and it is a standard REST API for one thing: keeping a list of users and groups in one system in step with another.

Without it, every integration invents its own endpoint for "create a user", and you end up with custom scripts for each application.

SCIM 2.0 defines the shared shape, so a source of truth such as an identity platform can push changes to many applications the same way.

The standards are RFC 7643 (the schema: what a User and Group look like), RFC 7644 (the protocol: how you call the API) and RFC 7642 (the use cases and concepts). If you only read one, make it RFC 7644.

Two roles, two directions

A SCIM exchange always has a client and a server.

  • The SCIM server exposes the endpoints and stores the resources. This is typically the application being provisioned.
  • The SCIM client calls them. This is typically the system that knows who should exist.

An identity platform can play both roles at different points. It can be a server for an HR system that pushes employee records in (inbound), and a client that pushes accounts out to applications (outbound).

See the glossary for the short definition.

Tip

Test one joiner, one mover and one leaver end to end before you trust the connection.

The core resources

User carries identifiers and attributes: userName, name, emails, active, an externalId that is the client's own key, and the server-assigned id.

Group has a displayName and a list of members, each referencing a user id.

Both have a meta block with creation and modification times. Enterprise attributes such as department, manager and employee number live in a standard extension schema, urn:ietf:params:scim:schemas:extension:enterprise:2.0:User.

The endpoints

All paths hang off a base URL, authenticated typically with a bearer token (RFC 6750).

ActionRequest
Create a userPOST /Users
Read oneGET /Users/{id}
SearchGET /Users?filter=...
ReplacePUT /Users/{id}
Partial updatePATCH /Users/{id}
DeleteDELETE /Users/{id}

The same set exists for /Groups. A server also publishes /ServiceProviderConfig, /ResourceTypes and /Schemas so a client can discover what is supported, such as whether PATCH or filtering is available.

A small example

Creating a user:

POST /scim/v2/Users
Content-Type: application/scim+json

{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "externalId": "EMP-10482",
  "userName": "asha.rao@example.com",
  "name": { "givenName": "Asha", "familyName": "Rao" },
  "emails": [{ "value": "asha.rao@example.com", "primary": true }],
  "active": true
}

The server responds 201 Created with the full resource, including its own id. Keep that id and the externalId mapping; you will need them.

Filtering

To find a user before creating, which avoids duplicates, use a filter:

GET /scim/v2/Users?filter=userName eq "asha.rao@example.com"

Operators include eq, ne, co (contains), sw (starts with), pr (present), plus and, or. The response is a ListResponse with totalResults and Resources. Large result sets use startIndex and count, and note that SCIM indexes start at 1, not 0.

PATCH, and the one that matters most

PUT replaces the whole object, which is risky if the client does not know every attribute the server holds. PATCH changes only what you name, using operations add, replace and remove.

Disabling a user, which is the single most important call in offboarding:

PATCH /scim/v2/Users/2819c223
{
  "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
  "Operations": [
    { "op": "replace", "path": "active", "value": false }
  ]
}

Be aware that some servers implement PATCH loosely. Differences you may meet: value passed as an object when the path is omitted, string "False" instead of boolean false, or no support for filtered paths such as emails[type eq "work"].value.

Test each target application's behaviour rather than trusting the spec.

Soft delete versus hard delete

This is the most common design question, and there is no single right answer.

  • Deactivate (active=false) keeps the account and its data but blocks sign-in. It is reversible and preserves ownership of records, which is helpful for rehires and audits.
  • Delete (DELETE) removes the resource. Many applications also delete or orphan the user's content, and it may be impossible to undo.

Reasonable default: deactivate on departure, and delete after a retention period you have chosen on purpose. Some applications treat deactivation as releasing a paid licence, others do not; confirm with the application's documentation.

For data-protection thinking about how long to keep things, see What the DPDP Act means for employee data.

Groups and entitlements

Groups are the usual vehicle for access: put the user in finance-approvers and the application maps that to a role. When you use groups:

  • Decide whether groups are owned by the source system or the application, never both.
  • Add and remove members with PATCH on the group, not by replacing the whole list.
  • Expect membership to take effect when the user next signs in, in some applications.

Common failure modes

  1. Duplicates, because the client created without searching on userName or externalId first.
  2. Rate limits. A first sync of ten thousand users can hit them; batch and back off on 429.
  3. Attribute mismatches, such as the application requiring a field the source does not provide.
  4. Drift. Someone edits a user directly in the application, and the next sync overwrites or ignores it. Decide which side wins.
  5. Silent failures. A provisioning job that errors on one user and carries on. Alert on failed operations and review them.

How AuthMantra uses it

AuthMantra offers a SCIM 2.0 server that accepts inbound records from HR systems, and outbound SCIM provisioning to applications that support it. That lets a change at the source, including deactivation, reach connected applications without a person re-typing it.

The joiner-mover-leaver use case walks through the flow.

What to do this week

  • List the applications you use that advertise SCIM support, and which of them put it behind a higher pricing tier.
  • For one application, run a test: create, patch active to false, and confirm the user can no longer sign in.
  • Decide and write down your delete policy: deactivate immediately, delete after how many days?
  • Choose the field that will serve as externalId, and make sure it never gets reused.
  • Add an alert for any failed provisioning call.

Try it

SCIMProvisioningJIT provisioningJMLAudit log