Automating user provisioning with SCIM 2.0: understanding the REST protocol for cross-system identity management, CRUD and search operations for users and groups, installing the SCIM extension in Keycloak with OAuth2 authentication, example integrations with Okta and Azure AD, and best practices for idempotent operations.

In episode 16 you opened social login through identity brokering and linked external accounts to internal identities. Episode 17 completes the identity lifecycle from the other side: provisioning. You'll learn SCIM 2.0 — the REST protocol for creating, updating, and deleting users and groups across systems automatically — so onboarding new employees is no longer manual work, but a consistent data flow from the HR system all the way to Keycloak.
SCIM (System for Cross-domain Identity Management) 2.0 is a specification that standardizes how identity systems exchange user data. Its main roles are three:
One important principle: provisioning is different from authentication. SCIM takes care of who exists in the system; authentication takes care of who signs in. Both work side by side — SCIM ensures new users already exist in Keycloak before they try to log in.
SCIM models the main resources as User and Group, each with its own endpoint:
| Operation | Method and endpoint | Function |
|---|---|---|
| Create | POST /Users | Create a new user |
| Read | GET /Users then the user identifier | Fetch one user's data |
| Update | PUT or PATCH /Users then the user identifier | Replace all or part of the attributes |
| Delete | DELETE /Users then the user identifier | Delete or disable a user |
| Search | GET /Users with filter parameters | Find users matching criteria |
| Groups | CRUD on /Groups | Manage groups and membership |
An example call via curl:
curl -X POST https://scim.example.com/v2/Users \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"budi","active":true,
"emails":[{"value":"budi@example.com","primary":true}]}'
curl -X PATCH https://scim.example.com/v2/Users/7f3c9a2d \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations":[{"op":"replace","path":"active","value":false}]}'POST /Users creates a user; PATCH with op set to replace can immediately disable an account by changing active to false — this is the common deprovisioning pattern. Every resource carries the schema urn:ietf:params:scim:schemas:core:2.0:User that marks its standard structure.
SCIM provides structured search through the filter parameter. For example GET /Users with the filter filter=userName eq "budi" or filter=active eq false. This is what synchronization uses to find the differences between two systems.
SCIM support in Keycloak comes through an extension — not a built-in feature of the standard installation. You add the SCIM extension as a module to the Keycloak server:
1. Download the SCIM extension matching your Keycloak version
2. Place the extension JAR into Keycloak's providers directory
3. Restart the Keycloak server
4. Register the SCIM credentials in the configuration (token or OAuth2)
5. Find the SCIM endpoint exposed for your realm
6. Test with a provisioning client such as Okta or Azure ADOnce the extension is active, Keycloak exposes per-realm SCIM endpoints that can accept calls from other systems. Authentication uses OAuth2 — the sending system (SCIM client) obtains a token via client credentials, then uses it on every SCIM call. This is consistent with the machine-to-machine pattern you learned in episode 6.
Authorization: Bearer in the header carries that token. Never send tokens in a URL — they can leak through logs and server history.
The SCIM schema and the Keycloak user model aren't always identical. The extension provides attribute mapping: for example SCIM userName to the Keycloak username, emails to the email attribute, and active to the enabled status. Correct mapping here determines whether users from the HR system arrive in Keycloak with complete data.
Tip
Start with read and search operations: make sure you can GET /Users and filter users from another system before turning on automatic provisioning. Verify reads first, then writes.
Several integration patterns are common in the field:
Although SCIM simplifies provisioning, some discipline keeps the system healthy:
active to false twice must not cause an error; this makes retries safe.Important
Never permanently delete users during deprovisioning. Disable first (set active to false) — deleting identity data destroys the audit trail and makes old accounts impossible to trace back.
In this episode 17, you automated user provisioning with SCIM 2.0: understanding SCIM's role as a REST API for identity management; mastering create, read, update, delete, and search operations for users and groups; enabling the SCIM extension in Keycloak with OAuth2 authentication; seeing integration patterns with Okta, Azure AD, and HR systems; and applying the practices of idempotency, error handling, rate limiting, and webhooks.
Key takeaways:
In the next episode (episode 18), we move into access control itself: groups and roles — building group hierarchies, realm roles and client roles, composite roles, and applying RBAC and ABAC in applications.