Configure SCIM Provisioning with Microsoft Entra ID
This guide describes how to configure Microsoft Entra ID to provision users and groups to AtScale Keycloak using Keycloak's native scim-api.
This integration supports the following:
- OAuth 2.0 client credentials authentication
- User provisioning, deprovisioning, and profile updates
- Group provisioning and membership synchronization
- Import/read operations from Keycloak
Integration overview
The integration uses the following flow: Microsoft Entra ID > HTTPS > Keycloak SCIM API.
Keycloak exposes the SCIM API at https://<atscale-host>/auth/realms/atscale/scim/v2. The OAuth token endpoint is https://<atscale-host>/auth/realms/atscale/protocol/openid-connect/token.
Entra ID authenticates using the OAuth 2.0 client credentials grant and sends a bearer token when calling the SCIM API.
Prerequisites
Before configuring SCIM provisioning with Entra ID, ensure you meet the following requirements:
- You have administrator access for both AtScale and Entra ID.
- AtScale is running Keycloak 26.7.x or later.
- The SCIM endpoint is reachable from Entra ID over HTTPS.
Enable and configure SCIM provisioning in Keycloak
First, you must enable and configure SCIM in AtScale's Keycloak instance.
-
Enable the SCIM API in Keycloak. To do this, add the
scim-apito the Keycloak feature's startup arguments. For example:keycloak:
extraStartupArgs: --import-realm --features=token-exchange,admin-fine-grained-authz:v1,opentelemetry-logs,scim-api --log=console --hostname-backchannel-dynamic trueOnce this has been set, the Keycloak startup log should show:
Preview features enabled: scim-api:v1 -
Enable SCIM for the atscale realm in Keycloak:
-
Log in to Design Center and click Security in the sidebar. Keycloak opens.
-
In the sidebar, under Configure, click Realm settings.
-
On the General tab, enable the SCIM API option.
The resulting SCIM base URL is
https://<atscale-host>/auth/realms/atscale/scim/v2. Note that the/authportion of the URL is required.
-
-
Create a Keycloak User Profile attribute for the SCIM
externalIdfield. For example:{
"name": "myExternalId",
"displayName": "External ID",
"multivalued": false,
"permissions": {
"view": ["admin"],
"edit": ["admin"]
},
"annotations": {
"kc.scim.schema.attribute": "externalId"
}
}ImportantThe annotation key must be
kc.scim.schema.attribute. Usingscim.schema.attributewill not work. This mapping is required so that the SCIMexternalIdvalue can be stored and subsequently returned by Keycloak. -
Create a confidential client for SCIM:
-
In the sidebar, click Clients.
-
Click Create client.
-
On the General settings tab, complete the following fields:
- Client type: Leave this set to OpenID Connect.
- Client ID: Enter
scim-client.
-
Click Next.
-
On the Capability config tab, complete the following fields:
- Client authentication: Enable this option.
- Authentication flow: Disable Standard flow (if it is not required for this client), and enable Service accounts roles.
-
-
Assign the
scim-clientthemanage-usersrole. This provides the permissions required for the SCIM user lifecycle.- Open the
scim-clientyou just created and go to the Service account roles tab. - Click Assign role.
- In the Assign roles to scim-client window, select the
manage-usersrole. - Click Assign.
- Open the
-
Configure the SCIM audience. The Entra ID provisioning configuration does not provide a field for specifying an OAuth audience, so you need to add the SCIM audience to the Keycloak access token. Without this, SCIM requests will be rejected with
401 Unauthorized, even if the OAuth token is valid.-
Open the
scim-clientand go to the Client scopes tab. -
Click the
scim-client-dedicatedscope. -
Click Configure a new mapper and select Audience.
-
Complete the following fields:
- Name: Enter a name for the mapper.
- Included Custom Audience: Enter the SCIM base URL,
https://<atscale-host>/auth/realms/atscale/scim/v2. - Add to access token: Enable this option.
-
Click Next, then click Save.
-
-
Obtain the client secret for the
scim-client. You will need this later when configuring Entra ID.-
Open the
scim-client. -
Go to the Credentials tab and copy the Client Secret.
ImportantDo not regenerate the Client Secret.
-
Enable and configure SCIM provisioning in Microsoft Entra ID
Once you have enabled SCIM in Keycloak, you can configure it in Entra ID.
Add an application in Entra ID
First, create an Enterprise application in Entra ID.
- In the Microsoft Entra admin center, go to Enterprise apps and click New application.
- Click Create your own application.
- Give the app a name.
- Select Integrate any other application you don't find in the gallery (Non-gallery).
- Click Create.
Configure the SCIM connection
Next, configure a SCIM connection for the application.
-
Open the application you created above and go to Provisioning > Connect your application.
-
Complete the following fields:
- Authentication method: Set to OAuth2 client credentials grant.
- Tenant URL: Enter
https://<atscale-host>/auth/realms/atscale/scim/v2. - OAuth token endpoint: Enter
https://<atscale-host>/auth/realms/atscale/protocol/openid-connect/token. - Client identifier: Enter
scim-client. - Client secret: Enter the
scim-clientsecret you copied from Keycloak.
-
Click Test connection. The connection must succeed before continuing.
Configure user attribute mappings
Next, you need to configure user attribute mappings in Entra ID. Go to Provisioning > Mappings > Provision Microsoft Entra ID Users and review the default mappings. Be sure to set the following.
| SCIM Attribute | Recommended Entra ID Source |
|---|---|
userName | User Principal Name |
externalId | objectId1 |
name.givenName | Given name |
name.familyName | Surname |
emails[type eq "work"].value | mail or userPrincipalName2 |
1 It is recommended that you map the SCIM externalId attribute to objectId in Entra ID. This is because the objectId is a stable value, as opposed to email-based values, which can change. This allows the provisioning system to maintain a stable identity match.
2 Keycloak requires an email value for user creation when the email attribute is configured as required. Some Entra ID users, especially cloud-only test users, may not have a populated mail attribute. In that case, the default mapping of emails[type eq "work"].value to mail can result in the emails attribute being omitted. For environments where mail is not consistently populated, you should map emails[type eq "work"].value to userPrincipalName to ensure the SCIM user always has an email value.
Enable provisioning
After the connection and user attribute mappings have been configured, you can enable the provisioning job. This job is responsible for synchronizing the complete user/group state.
- In Entra ID, go to Manage > Provisioning.
- Set Provisioning Status to On.
- Click Save.
Be sure to use the Provisioning Status control under Manage > Provisioning, rather than the Start provisioning button shown on the application Overview page.
Assign users and groups
Use the Enterprise application assignment controls to determine which Entra ID users and groups are provisioned to Keycloak. AtScale recommends the following rollout strategy:
- Start with a dedicated test user.
- Assign the test user to the Enterprise application.
- Run Provision on demand.
- Verify the user in Keycloak.
- Validate profile updates.
- Validate deprovisioning.
- Add the required production users/groups.
Use application assignments to control the provisioning scope.
Working with SCIM provisioning
User provisioning
Entra ID can provision a user to Keycloak using the SCIM /Users endpoint. A typical SCIM user contains the following attributes:
{
"userName": "user@example.com",
"externalId": "<entra-object-id>",
"active": true,
"name": {
"givenName": "First",
"familyName": "Last"
}
}
After provisioning, the user should be visible in Keycloak.
User profile updates
Changes to mapped Entra ID attributes are propagated to Keycloak through SCIM. For example, Entra ID Surname > SCIM name.familyName > Keycloak lastName.
Use Provision on demand for an immediate validation, or allow the normal provisioning cycle to process the change.
User deprovisioning
When an assigned Entra ID user is disabled or removed from the provisioning scope, Entra ID sends the corresponding SCIM deactivation. This results in the user's account being deactivated in Keycloak. Note that the user is not deleted.
Deactivation prevents subsequent authentication, but existing Keycloak sessions/tokens are not necessarily revoked immediately. Existing sessions can remain valid until their normal expiration.
Group provisioning
Entra ID can provision groups to Keycloak through the SCIM /Groups endpoint. A group creation request contains the following attributes:
{
"displayName": "example-group",
"externalId": "<entra-group-object-id>"
}
Entra ID does not include the complete members array when creating the group. This is compatible with native Keycloak SCIM.
Group membership synchronization
Group membership is synchronized separately from group object creation. The expected flow is as follows:
- Entra ID creates the group in Keycloak.
- The provisioning cycle runs.
- Entra ID synchronizes the group membership.
- Keycloak reflects the membership on both the group and user resources.
Provision on demand can create/update the group object, but group membership is synchronized by the scheduled provisioning cycle. To validate group membership:
- In Entra ID, go to Manage > Provisioning.
- Set Provisioning Status to On.
- Click Save.
- Allow the provisioning cycle to run.
- Verify the membership in Keycloak.
Import/read operations
When determining whether users already exist, Entra ID reads existing Keycloak users through the SCIM /Users endpoint. This allows Entra ID to read users from Keycloak, match existing users, determine the provisioning scope, and maintain the provisioning relationship.
During the provisioning process, users always move from Entra ID to Keycloak. Keycloak does not independently pull users from Entra ID.
Expected supported lifecycle
The supported Entra ID to Keycloak lifecycle for users is as follows:
- A user is created in Entra ID.
- The user is provisioned via SCIM.
- The user is created in Keycloak.
- The user's profile changes.
- The corresponding Keycloak user is updated.
- The Entra ID user is disabled or removed from scope.
- The user is deactivated via SCIM.
- The user is disabled in Keycloak.
For groups, the lifecycle is:
- A group is created in Entra ID.
- The group is created in SCIM.
- The provisioning cycle runs.
- Group membership is synchronized.
- Keycloak group membership is updated.
Recommended production configuration
For a production deployment:
- Use the native Keycloak
scim-api. - Use a dedicated confidential
scim-client. - Use OAuth 2.0 client credentials.
- Store the client secret securely.
- Grant only the permissions required for SCIM provisioning.
- Configure the SCIM audience mapper.
- Map the Entra ID
objectIdattribute to SCIM'sexternalId. - Ensure every provisioned user has a valid email value.
- Exclude Keycloak/AtScale administrative users from SCIM assignments.
- Start with a small test assignment before enabling production users.
- Keep group membership synchronization enabled through the normal provisioning cycle.
Validation checklist
Use the following checklist when configuring a new environment.
| Capability | Expected Result |
|---|---|
| OAuth 2.0 client credentials | Supported |
| Test connection | Successful |
| Read users/matching | Supported |
| User provisioning | Supported |
| User profile updates | Supported |
| User deprovisioning | Supported |
| Group creation | Supported |
| Group membership synchronization | Supported |
Stable externalId | Supported |
| Import/read from Keycloak | Supported |
Known limitations and important behavior
Email must be available
Keycloak requires an email value when the email attribute is configured as required. If an Entra ID user has no mail value, map emails[type eq "work"].value to userPrincipalName.
Use a stable externalId
It is recommended that you map externalId to objectId. Avoid using mutable values such as email addresses as the primary external identity.
Keycloak admin users should not be provisioned through SCIM
Users holding Keycloak administrative roles can be protected from SCIM modification. Do not include AtScale/Keycloak administrative accounts in the Entra ID SCIM assignment scope. Use dedicated application assignments for regular users.
Active sessions are not immediately revoked
SCIM deactivation changes the Keycloak user state to disabled. It does not necessarily invalidate already-issued sessions or tokens immediately.
Troubleshooting
401 Unauthorized error from the SCIM API
Verify the following:
- Keycloak
scim-apiis enabled. - Realm SCIM API is enabled.
- The OAuth client is confidential.
- The service account has the
manage-usersrole. - The client secret is correct.
- The audience mapper is configured.
- The audience exactly matches
https://<atscale-host>/auth/realms/atscale/scim/v2.
User creation fails with a "Please specify email" error
Check the Entra ID attribute mapping of emails[type eq "work"].value. If the user's mail attribute is empty, map the source to userPrincipalName.
Group is created but membership is missing
Check that the provisioning job is enabled:
- In Entra ID, go to Manage > Provisioning.
- Set Provisioning Status to On.
- Click Save.
Group creation and group membership synchronization are separate operations. Membership is handled by the provisioning cycle.
Existing users are not matched
Check the externalId configuration. AtScale recommends mapping objectId in Entra ID to externalId. Also verify that Keycloak has the User Profile attribute annotated with kc.scim.schema.attribute = externalId.