This project provides a SCIM 2.0-compliant extension for Keycloak, enabling SCIM-based user and group provisioning. It supports:
- Realm-level SCIM APIs:
/realms/{realm}/scim/v2 - Organization-level SCIM APIs (Keycloak 26+ with Organizations):
/realms/{realm}/scim/v2/organizations/{organizationId}
- Keycloak: This extension is developed for Keycloak 26.1.4. It may work with other versions, but compatibility is not guaranteed.
- Java: Java 21 is required to build the project.
Easiest way to use the extension is to download a JAR file from GitHub packages.
- Download the latest JAR from: GitHub Packages
- Copy it to your Keycloak instance:
cp keycloak-scim-server-*.jar $KEYCLOAK_HOME/providers/- Restart Keycloak.
- Build the extension:
./gradlew build- Copy the built JAR file from
build/libs/keycloak-scim-server-<version>.jarto the Keycloak providers directory:
cp build/libs/keycloak-scim-server-*.jar $KEYCLOAK_HOME/providers/Configuration on instance level is done by defining environment variables in the Keycloak server.
The following environment variables are available:
| Setting | Value |
|---|---|
| SCIM_AUTHENTICATION_MODE | Authentication mode for SCIM API. Possible values are KEYCLOAK and EXTERNAL. If the value is not set the server will respond unauthorzed for all requests. |
| SCIM_EXTERNAL_ISSUER | Issuer for the external authentication. This is used to validate the JWT token. |
| SCIM_EXTERNAL_AUDIENCE | JWKS URI for the external authentication. This is used to validate the JWT token. |
| SCIM_EXTERNAL_JWKS_URI | Audience for the external authentication. This is used to validate the JWT token. |
| SCIM_EXTERNAL_SHARED_SECRET | Shared secret value used for request authentication/validation. |
| SCIM_EXTERNAL_SHARED_SECRET_HASH_ALGORITHM | PHC String Format representing hash algorithms and its parameters, used for request authentication/validation (must be on of the following). |
The following REST call can be called through the Keycloak Admin API to store the settings under realm attributes.
PUT /admin/realms/{realm}
{
"attributes": {
"scim.authentication.mode": "EXTERNAL|INTERNAL",
"scim.external.issuer": "string",
"scim.external.jwks.uri": "string",
"scim.external.audience": "string",
"scim.external.shared.secret": "string",
"scim.external.shared.secret.hash.algorithm": "string"
}
}
Configuration on organization level is done by defining organization attributes in the Keycloak server. The following organization attributes are available:
| Setting | Value |
|---|---|
| SCIM_AUTHENTICATION_MODE | Authentication mode for SCIM API. Possible values are KEYCLOAK and EXTERNAL. If the value is not set the server will respond unauthorzed for all requests. Currently on organization level only EXTERNAL is supported. |
| SCIM_EXTERNAL_ISSUER | Issuer for the external authentication. This is used to validate the JWT token. |
| SCIM_EXTERNAL_AUDIENCE | Audience for the external authentication. This is used to validate the JWT token. |
| SCIM_EXTERNAL_JWKS_URI | JWKS URI for the external authentication. This is used to validate the JWT token. |
| SCIM_LINK_IDP | Enables support for linking organization identity provider with user. |
| SCIM_EMAIL_AS_USERNAME | Forces server to user email as username instead of actual username. When this setting is enabled username will be unaffected by any update operations. This setting is currently supported only in organization level configuration |
| SCIM_EXTERNAL_SHARED_SECRET | Shared secret value used for request authentication/validation. |
| SCIM_EXTERNAL_SHARED_SECRET_HASH_ALGORITHM | PHC String Format representing hash algorithms and its parameters, used for request authentication/validation (must be on of the following). |
This extension is compatible with Microsoft Entra ID SCIM provisioning.
Before Entra ID can provision users and groups to Keycloak via SCIM, you need to configure SCIM authentication settings.
These settings can be applied either:
- At the realm level (for /realms/{realm}/scim/v2)
- Or at the organization level (for /realms/organizations/scim/v2/organizations/{organizationId})
For more details, refer to the sections [Configuration on Realm Level] and [Configuration on Organization Level in this document].
SCIM Settings for Entra ID
When using Entra ID settings will be following:
| Setting | Value |
|---|---|
| SCIM_AUTHENTICATION_MODE | EXTERNAL |
| SCIM_EXTERNAL_ISSUER | https://sts.windows.net/<your-tenant-id>/ |
| SCIM_EXTERNAL_AUDIENCE | 8adf8e6e-67b2-4cf2-a259-e3dc5476c621 |
| SCIM_EXTERNAL_JWKS_URI | https://login.microsoftonline.com/<your-tenant-id>/discovery/v2.0/keys |
Replace with your actual Azure tenant ID.
- SCIM_AUTHENTICATION_MODE enables external authentication support for the SCIM server. In this case the external authentication source will be the Azure Entra ID.
- SCIM_EXTERNAL_ISSUER ensures the JWT token was issued by your tenant.
- SCIM_EXTERNAL_AUDIENCE must be exactly 8adf8e6e-67b2-4cf2-a259-e3dc5476c621 — this is the default audience used by Entra ID for non-gallery applications.
- SCIM_EXTERNAL_JWKS_URI allows Keycloak to fetch public keys for token validation.
OR
| Setting | Value |
|---|---|
| SCIM_AUTHENTICATION_MODE | EXTERNAL |
| SCIM_EXTERNAL_SHARED_SECRET | <token_hashed_value> |
Replace <token_hashed_value> with your hashed token value (using SHA-512 Hex).
Step-by-step guide on the Azure:
- Sign in to the Azure portal
- Go to Identity → Applications → Enterprise applications
- Click + New application → + Create your own application
- Enter a name for your application (e.g., My Keycloak SCIM).
- Choose Integrate any other application you don't find in the gallery.
- Click Create to create the application. The application will open automatically in its management screen.
- In the application's left-hand menu, select Provisioning.
- Click + New configuration.
- Fill in the following:
- Tenant URL (realm): https://mykeycloak.example.com/realms/my-realm/scim/v2 or
- Tenant URL (organization): https://mykeycloak.example.com/realms/my-realm/scim/v2/organizations/{organizationId}
- Secret Token: Leave this field empty (the application will use the Entra ID bearer token) OR enter the shared secret value (not hashed).
- Click Test Connection to verify the SCIM endpoint.
- Click Create.
- Navigate to Attribute Mapping (Preview).
- Open Provision Microsoft Entra ID Groups.
- Set Enabled to No.
- Click Save.
- Go back → open Provision Microsoft Entra ID Users.
- Open Provision Microsoft Entra ID Users.
- Define mappings, following are required for Keycloak extension:
- userName
- active
- emails[type eq "work"].value
- name.givenName
- name.familyName
- Click Save.
- Go back to Provisioning.
- Set Provisioning Status to On.
- Click Save.
- Reload the page to ensure the configuration was saved.
- Navigate to Manage > Users and groups > + Add user/group.
- Select the user you want to provision and click Assign.
- Navigate to Provision on demand.
- Find the user you just assigned.
- Click on the user and select Provision.
- Verify that the provisioning completes successfully.
For more information, refer to the following documents:
https://learn.microsoft.com/en-us/entra/identity/saas-apps/tutorial-list
Identity Provider linking with Entra ID requires a few additional configuration steps on both the Entra and Keycloak sides.
Step 1: Add externalId
In the Keycloak admin console, ensure that you have externalId attribute defined in your Realm Settings > User Profile. This attribute is used to store user's external id in the Keycloak side and without it the Identity Provider linking will fail.
Step 2: Map externalId in SCIM provisioning
In the Entra Id, make sure that the objectId from Entra ID is mapped into the SCIM externalId field:
- Navigate to your Enterprise Application > Provisioning > Attribute Mapping (Preview) > Provision Microsoft Entra ID Users.
- Click Add New Mapping.
- Set:
- Source attribute: objectId
- Target attribute: externalId
- Click Save.
This ensures that during SCIM provisioning, the Entra objectId is stored in Keycloak as the user’s externalId, which will later be used for identity linking.
Step 3: Configure Keycloak Identity Provider to Use Object ID
Next, configure your Entra ID Identity Provider in Keycloak to use the oid claim from the login token instead of the default sub claim (which is app-specific).
- Navigate to Identity Providers > select your Entra ID provider.
- Go to the Mappers tab.
- Click Add Mapper.
- Fill in the mapper details:
- Name: map_oid_as_brokerid (or any descriptive name)
- Sync Mode: Force
- Mapper Type: Username Template Importer
- Template: ${CLAIM.oid}
- Target: BROKER_ID
- Click Save.
This mapper tells Keycloak to use the Entra oid claim as the Broker ID, ensuring that the login user is matched correctly with the SCIM-provisioned user.
Step 4: Enable Identity Provider Linking in SCIM
Finally, instruct your SCIM server to automatically link users to the configured Identity Provider during provisioning:
Add the following attribute to your SCIM configuration (only supported by organization server currently):
SCIM_LINK_IDP=true
This will ensure that when a user is provisioned via SCIM, a corresponding Identity Provider link is also created automatically based on the externalId / oid.
By default, the SCIM server only exposes users who are explicitly assigned the scim-managed role within the realm. This ensures that only users intended to be managed through SCIM are returned or modifiable via SCIM API operations.
This prevents accidental exposure or modification of users that were:
- created manually via the Keycloak admin UI
- imported from external identity providers
- or otherwise not intended to be managed through SCIM
If you want to expose all users (i.e., bypass filtering), you can simply assign the scim-managed role to every user. This effectively disables the filter, making the SCIM behavior equivalent to an unfiltered list.
This role-based filtering applies to all SCIM operations, including:
- GET /Users
- PATCH /Users/{id}
- DELETE /Users/{id}
Users without the scim-managed role will be invisible to SCIM clients — they won’t be listed, updated, or removed through SCIM.
This filtering mechanism is designed to improve safety, especially in complex deployments involving federated users, legacy accounts, or overlapping identity sources (such as Entra ID + local users).
This design does mean that provisioning a user through SCIM who previously existed without the role may cause conflicts or provisioning failures if role assignment isn’t handled correctly. However, this is a deliberate design choice to provide fine-grained control over which users are SCIM-visible.