![]()
Keycloak Migration Guide
This guide provides step-by-step instructions for a successful migration from Keycloak to Descope.
There are two main paths to migrate Keycloak users to Descope:
- Full Migration - You completely migrate your users and identity providers from Keycloak into Descope and retire Keycloak.
 - Just-in-Time (JIT) Provisioning - You progressively migrate users into Descope as they log in. Descope verifies their existing Keycloak password via Keycloak's API, then creates their user record locally.
 
Keycloak vs. Descope Terminology
Keycloak and Descope use similar identity concepts, but they differ in how user isolation works.
| Keycloak Concept | Descope Equivalent | Description | 
|---|---|---|
| Realm | Project | A Keycloak Realm is a fully isolated identity domain. Descope's equivalent isolation boundary is a Project. | 
| User | User | A person's identity record. In Descope, users are global within a project and can belong to multiple tenants. | 
| Group / Organization | Tenant | Keycloak groups or organizations map to Descope tenants. Tenants define contextual membership and permissions but share the same user base. | 
| Role | Role | Keycloak Roles map directly to Descope Roles. | 
| Client (Application) | Application | OAuth2/OIDC clients in both systems serve the same purpose. | 
| Identity Provider (OIDC/SAML) | SSO Connection | Both systems use external IdPs for authentication and federation. | 
In short: Keycloak Realms are effectively Projects and Keycloak Groups/Organizations are Tenants.
Exporting Users from Keycloak
You can export users either via the Admin REST API or directly from the Keycloak database.
Export via REST API
Export the result as CSV or JSON for easier transformation.
Importing Users into Descope
Use the Descope Management API or Batch Create Users API to import users.
Refer to the Custom Data Store Migration Guide for detailed JSON formatting and password import examples.
Example import payload:
Password Migration
Note
If you would like to move fully to passwordless authentication, as long as your users have a verified email address associated with their account, you can skip this step.
Keycloak's default password hashing algorithm is PBKDF2-SHA256 (≈ 27,500 iterations).
You can confirm the algorithm from the CREDENTIAL table or export file.
Descope supports a variety of password hashing algorithms. You can see the full list of supported algorithms here.
If you export the hash, salt, and iterations, you can import passwords so users don't need to reset them.
Otherwise, you'll need to trigger a password reset for the user through Descope Flows post-migration.
Migrating Roles and Tenants
Keycloak Roles map directly to Descope Roles, and Groups or organizations in Keycloak should become Tenants in Descope.
It's worth noting that users in Descope can belong to multiple tenants at the same time.
Migrating Identity Providers
If your realm has connected IdPs (e.g., Google, GitHub, Azure AD):
- OIDC IdPs → Recreate as Custom OAuth Providers or Tenant OIDC SSO Connections
 - SAML IdPs → Recreate as Tenant SAML SSO Connections
 
Specifically with OIDC, reusing client IDs, secrets, and redirect URIs ensures seamless continuity. You'll have to add the Descope Redirect URI to the IdP's list of authorized callback URLs, but other than that, you should be able to reuse the same IdP configuration.
Whether you use a Custom OAuth Provider or a Tenant OIDC SSO Connection, is dependent on whether or not all users or just specific Keycloak users (such as part of a group or organization) should be able to use the IdP to login to Descope. Tenant SSO connections are usually reserved for a specific group of users that exist as/within a Descope Tenant.
With SAML, if you do not want to have to re-configure your IdP to use the Descope SSO URL and Entity ID, you can refer to our SSO Migration Guide for more information.
If user emails differ between the IdP and Descope, a new user may be created during first login. Use IdP subject identifiers when available for linking.
Just-in-Time (JIT) Provisioning Migration with Password Validation
This method allows Descope to create users dynamically as they log in — validating their credentials through Keycloak in real-time.
This is ideal when you don't have access to password hashes, but still want a smooth, password-based transition.
Important
This JIT method only works if all users belong to a single Keycloak realm, or if you can reliably determine which realm to authenticate against.
If users span multiple realms and you can't infer their realm from input, this approach may not be viable.
How It Works
- 
A user enters their email/username and password in a Descope Flow.
 - 
Descope calls your backend webhook.
 - 
Your backend sends a
POSTrequest to Keycloak's token endpoint for that realm: - 
If Keycloak responds
200 OK, the credentials are valid. - 
Descope creates a user in your project using the Management API with the same password.
 - 
The user is now fully migrated and can authenticate directly through Descope going forward.
 
Requirements
- Direct Access Grants (a.k.a. Resource Owner Password Credentials flow) must be enabled for your Keycloak client.
 - Keycloak must be reachable by your backend.
 
Security and Limitations
- The password grant flow is deprecated for public clients — only use this for temporary migration.
 - Protect your client credentials and restrict access to this endpoint.
 - Disable the direct-grant flow once all users have migrated.
 
Integration Flow Example
Below is an example flow for migrating users JIT with password validation:
![]()
- User submits credentials.
 - Descope Flow triggers your Generic HTTP Connector POST request to Keycloak's token endpoint.
 - Keycloak will validate the credentials and return a token if successful, with any additional user attributes as well.
 - On success, Descope will invoke the 
Sign Up / Passwordaction and create a new user with pre-existing password. We can also set custom attributes for the user here if we want. - After the migration, future logins for this user will happen directly with Descope, not invoking the connector anymore.
 
Transitioning Away from Keycloak
After the majority of users have logged in once (and thus migrated):
- Disable the Keycloak connection.
 - Switch your apps to use Descope SDKs directly.
 - Remove the password grant configuration in Keycloak.
 
Post-Migration: Handling Freshly Migrated Users
A common strategy when migrating users from Keycloak to Descope is to set a custom attribute on migrated users to track their migration status and customize their first login experience. This approach works for both full migration and JIT migration scenarios.
Setting the Migration Attribute
For Full Migration:
When you import users using the Management SDK or API, include a custom attribute like freshlyMigrated: true in the user payload:
For JIT Migration:
In your migration flow, after successfully validating credentials with Keycloak and creating the user, use the Update User / Attributes action to set the freshlyMigrated attribute to true.
Customizing Behavior for Migrated Users
Once the attribute is set, you can use conditional logic in your Descope flows to provide a tailored onboarding experience for users who just transitioned from Keycloak.
For example, you can:
- Prompt for MFA enrollment
 - Ask users to verify or update their email/phone
 - Request password reset (if passwords weren't migrated)
 - Show a welcome message explaining the migration
 
![]()
Clearing the Migration Flag
Once the user completes the onboarding flow, use the Update User / Attributes action to set freshlyMigrated to false. This ensures they won't see the migration prompts on subsequent logins.
![]()