Notes on building a SCIM endpoint from scratch
Ever had to deal with automated user provisioning? If you’ve ever integrated an enterprise identity provider (like Okta or Azure AD), chances are you’ve bumped into SCIM 2.0. It’s one of those specs that sounds simple—“standardized user provisioning”—until you dig in and realize...it’s a protocol prescribing with its own schema, rules, and quirks. At Scalekit, we were testing out what it’s like to build a production-ready SCIM 2.0 endpoint, and I want to share what I learned—so you don’t spend hours banging your head against a hard surface :-D Let’s roll... First things first: What is SCIM? SCIM (System for Cross-domain Identity Management) is a standard designed to make user provisioning and deprovisioning across services easier for enterprises. It prescribes a implementation for the your app and the enterprise to simplify the provisioning problem. Instead of IT teams manually creating and deleting user accounts in each and every app their organization maybe using, SCIM prescribes identity providers (IdPs) like Okta automatically manage users and groups inform your app. Imagine your app receives a POST /Users with user info whenever someone joins a company. Or a DELETE /Users/{id} when someone leaves. That’s SCIM magic right there. What your endpoint actually needs to do Here’s what you’re on the hook for if you want to say “yep, we support SCIM”: Authentication (usually HTTP Bearer tokens) CRUD support for /Users and /Groups endpoints JSON payloads that conform to RFC7643 and RFC7644 Pagination, filtering, patching... all the fun stuff Here’s a simple example of a SCIM-compliant user creation payload: { "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "userName": "jdoe@example.com", "name": { "givenName": "Jane", "familyName": "Doe" }, "emails": [ { "value": "jdoe@example.com", "primary": true } ] } And the POST /Users endpoint needs to parse that, validate it, and return a compliant response like: { "id": "abcd-1234", "userName": "jdoe@example.com", "active": true, ... } How I approached building it When I started implementing SCIM 2.0, I assumed I just needed to slap on a couple REST endpoints. Turns out, you need more than that to make the likes of Okta and Azure AD happy

Ever had to deal with automated user provisioning?
If you’ve ever integrated an enterprise identity provider (like Okta or Azure AD), chances are you’ve bumped into SCIM 2.0. It’s one of those specs that sounds simple—“standardized user provisioning”—until you dig in and realize...it’s a protocol prescribing with its own schema, rules, and quirks.
At Scalekit, we were testing out what it’s like to build a production-ready SCIM 2.0 endpoint, and I want to share what I learned—so you don’t spend hours banging your head against a hard surface :-D
Let’s roll...
First things first: What is SCIM?
SCIM (System for Cross-domain Identity Management) is a standard designed to make user provisioning and deprovisioning across services easier for enterprises. It prescribes a implementation for the your app and the enterprise to simplify the provisioning problem.
Instead of IT teams manually creating and deleting user accounts in each and every app their organization maybe using, SCIM prescribes identity providers (IdPs) like Okta automatically manage users and groups inform your app.
Imagine your app receives a POST /Users
with user info whenever someone joins a company. Or a DELETE /Users/{id}
when someone leaves. That’s SCIM magic right there.
What your endpoint actually needs to do
Here’s what you’re on the hook for if you want to say “yep, we support SCIM”:
- Authentication (usually HTTP Bearer tokens)
- CRUD support for
/Users
and/Groups
endpoints - JSON payloads that conform to RFC7643 and RFC7644
- Pagination, filtering, patching... all the fun stuff
Here’s a simple example of a SCIM-compliant user creation payload:
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "jdoe@example.com",
"name": {
"givenName": "Jane",
"familyName": "Doe"
},
"emails": [
{
"value": "jdoe@example.com",
"primary": true
}
]
}
And the POST /Users
endpoint needs to parse that, validate it, and return a compliant response like:
{
"id": "abcd-1234",
"userName": "jdoe@example.com",
"active": true,
...
}
How I approached building it
When I started implementing SCIM 2.0, I assumed I just needed to slap on a couple REST endpoints. Turns out, you need more than that to make the likes of Okta and Azure AD happy