Auth0 → Keycloak
Export Auth0 profiles with the Management API job, request password hashes separately, and import users into a Keycloak realm. Prove one real password on the Keycloak version you will run before you switch applications.
Should you make this move?
Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.
Auth0
- Mature federation, extensibility, enterprise connections, and migration tooling cover complex identity programs
- Centralized sign-in, federation, MFA, and user lifecycle controls reduce application security work
- Tenant configuration, actions, pricing, and Auth0-specific claims can create substantial lock-in
- Passwords, sessions, factors, identities, and authorization policy are unusually sensitive to migration errors
Keycloak
- Self-hosted realms, clients, and login flows keep identity on infrastructure you operate
- Centralized sign-in, federation, MFA, and user lifecycle controls reduce application security work
- Realm export, password algorithms, and custom providers make a cutover an operations project
- Passwords, sessions, factors, identities, and authorization policy are unusually sensitive to migration errors
Keycloak: Self-hosted realms, clients, and login flows keep identity on infrastructure you operate. This removes a major source-side concern: Tenant configuration, actions, pricing, and Auth0-specific claims can create substantial lock-in.
What you lose: Mature federation, extensibility, enterprise connections, and migration tooling cover complex identity programs. What you inherit: Realm export, password algorithms, and custom providers make a cutover an operations project.
Jump to a section
Know the shape of the move.
This timeline assumes
- Your Auth0 plan includes bulk export. Auth0 says that feature is not on the Free plan.
- You can open the support case Auth0 documents for a PGP-encrypted password-hash export if passwords must move.
- You can stop Keycloak nodes for a CLI import, or you will use partial import while the server stays up.
- Applications can be moved one by one. Auth0 stays available until a password test passes on production Keycloak.
- You treat vendor notes about bcrypt as version-specific. Phase Two and Skycloak disagree, so you test your own build.
What survives the move.
“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.
| Item | Outcome | Impact | What happens | Mitigation |
|---|---|---|---|---|
| User profiles | partial | critical | Auth0's bulk export is a job, JSON as NDJSON or CSV. CSV is limited to 30 fields and cannot carry app_metadata or user_metadata as whole objects. Job data is deleted after 24 hours. | Export JSON when you need metadata. Download the file the same day. Keep the Auth0 user id on the Keycloak user. |
| Password hashes | partial | critical | The bulk export does not include password hashes. Auth0 documents a separate support export, encrypted to your PGP key. Phase Two says Keycloak 26.7.4 has no built-in bcrypt hasher. Skycloak says a bcrypt credential can be stored directly. Those are vendor claims about their reading of Keycloak. | Request the hash file early. Import one user and sign in on the Keycloak version you will run. If that fails, use a reset or a bridge you have tested. |
| MFA secrets | partial | critical | Auth0's support article covers MFA secrets in the same PGP export path as password hashes. A profile export alone does not enroll authenticators in Keycloak. | Decide whether each factor is imported, reset, or left behind. Test one enrolled user. |
| Sessions and refresh tokens | lost | high | Keycloak says an export does not include persisted sessions, user and admin events, workflow state, or revoked tokens. People sign in again after cutover. | Plan the re-login. Do not promise that existing sessions survive. |
| Actions, Rules, and Hooks | manual | critical | Nothing in the Auth0 export jobs turns an Action into a Keycloak authentication flow. You rebuild the behavior. | List every Action that changes tokens or blocks logins. Reimplement it and test the same cases. |
| Social and enterprise connections | manual | critical | Connection configuration is tenant configuration, not a row in the user export. Users can carry identity links that have no matching Keycloak identity provider until you create one. | Create the providers first. Then import a user from each connection and sign in with it. |
| Organizations and roles | manual | high | Auth0 organizations, roles, and your own metadata keys need an explicit Keycloak mapping. Partial import can bring users, clients, roles, and groups when they are in the JSON you submit. | Map roles before the full import. Check one user from each role. |
| Admin Console export limits | partial | high | Keycloak's Admin Console partial export cannot export users, masks secrets with asterisks, and is not the backup path. The CLI export is the one Keycloak says is suitable for moving a realm. | Use kc.sh export and import for the realm you will keep. Do not treat realm-export.json from the console as the user file. |
| Large user files | partial | high | Keycloak says a single-file export or import can run out of memory, and tells you to export to a directory when the database has more than 50,000 users. Import file names have to follow the realm, users, and federated-users pattern. | Split large realms by directory. Confirm the file names before the production import. |
| Applications and secrets | manual | critical | Clients, callback URLs, and client secrets are recreated in Keycloak. The console masks secrets on the way out. Auth0 signing keys do not become Keycloak keys. | Register each application, rotate secrets, and verify the issuer and the audience your API expects. |
Where each thing goes.
| Source | Destination | Method | Notes |
|---|---|---|---|
| Auth0 user_id | Keycloak user attribute | transform | Keep the old id for reconciliation. |
| email and email_verified | email and emailVerified | transform | Check duplicates before import. |
| given_name and family_name | firstName and lastName | transform | Derive them when the export has a single name field. |
| blocked | enabled | transform | A blocked Auth0 user should not be an enabled Keycloak user. |
| user_metadata and app_metadata | User attributes | manual | CSV export will not carry these as whole objects. Use JSON. |
| Password hash | Keycloak credential or a reset | manual | Only the separate PGP export has the hash. Test one login. |
| MFA factor | Keycloak credential or a fresh enrollment | manual | Confirm the factor is in the support export before you promise it. |
| Connection or identity | Identity provider link | manual | The provider has to exist first. |
| Action or Rule | Flow, mapper, or custom provider | manual | There is no importer for this. |
Make the move recoverable.
Create the source-of-truth backup
Keep an Auth0 profile export and, if you requested it, the encrypted password file, before Keycloak becomes the issuer.
- Create the user-export job for each connection you will move. Prefer JSON.
- Download the result before the 24-hour job retention ends.
- Open the password-hash support case with the PGP key Auth0 specifies, if you need hashes.
- Export Keycloak as well once the pilot realm looks right, with nodes stopped for the CLI export.
Proof to capture: You have the NDJSON download and a note of which connections it includes. Password hashes, if any, are still encrypted to your key.
Profile file for partial import
Turn Auth0 NDJSON into a Keycloak user import without dropping the old id.
- Map email, verification, names, and the blocked flag.
- Store user_id in an attribute.
- Leave passwords out of this file unless a tested hasher is already in place.
- Import a batch of about a hundred users into a pilot realm before the full file.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
Password test
Find out whether this Keycloak build can verify the Auth0 hash you received.
- Decrypt the PGP file on your machine.
- Import a single user whose password you know.
- Sign in through the Keycloak account flow.
- If the login fails, stop the batch and choose a reset or a tested bridge.
Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.
The things most likely to hurt.
These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.
The profile export is mistaken for a password export
Users exist in Keycloak and none of them can sign in.
- Consequence
- You have a support spike on cutover day.
- Mitigation
- Treat the support file as a separate artifact and test one password.
Stop if: The single-user login fails.
Vendor bcrypt advice does not match your Keycloak build
A hash that one guide says will work is rejected, or the reverse.
- Consequence
- You either lock people out or you store hashes the server will not check.
- Mitigation
- Test the version you will run. Do not mix the two vendor procedures.
Stop if: The pilot login does not match the procedure you documented.
An Action still runs only in Auth0
Tokens issued by Keycloak are missing a claim or a block the Action used to apply.
- Consequence
- APIs authorize the wrong people.
- Mitigation
- Replay every token-changing Action against Keycloak before you switch that application.
Stop if: A required claim is missing.
Do the work in this order.
- Days 1 to 3 · inventory
List connections and Actions
6 to 12 hours active2 to 3 days elapsedApplication owners waiting- List database connections, social connections, Actions, and applications.
- Open the password export case if you need hashes.
Depends on: Auth0 tenant admin, Keycloak admin
Stop / go checkpointExport profiles?
Go when: Every application has an owner and a claim list.
Stop when: You cannot name the connections in use.
- Days 3 to 6 · backup
Download the export
4 to 8 hours active1 to 4 days elapsedExport job, and maybe the support case waiting- Run the export job and download it the same day.
- Store the file where the migration team can reach it.
Depends on: Approved inventory
Stop / go checkpointBuild the pilot?
Go when: The file's user count matches the connection.
Stop when: The download expired or metadata is missing.
- Days 6 to 14 · pilot
Import a pilot realm
10 to 24 hours active4 to 8 days elapsedPassword file, if you are waiting on it waiting- Import a small batch.
- Sign in as one known user.
- Rebuild one Action.
Depends on: Downloaded export
Stop / go checkpointMove an application?
Go when: The known user can sign in and the test token has the right claims.
Stop when: The password test fails or a claim is missing.
- Days 14 to 18 · cutover
Point applications at Keycloak
6 to 16 hours active2 to 5 days elapsedApplication deploys waiting- Import the remaining users.
- Switch one application, then the next.
- Keep Auth0 able to sign the old applications in.
Depends on: Passed pilot
Stop / go checkpointSwitch the next app?
Go when: The switched app accepts Keycloak tokens only, and logins succeed.
Stop when: A switched app still depends on an Auth0-only Action.
- Days 18 to 25 · observe
Watch logins
4 to 10 hours active3 to 7 days elapsedA full login cycle waiting- Watch failed logins and missing factors.
- Keep Auth0 until the rollback window ends.
Depends on: Verified cutover
Stop / go checkpointClose the Auth0 tenant?
Go when: Failed logins are understood and no rollback trigger fired.
Stop when: A connection or factor still fails.
Cut over with a way back.
Cutover
Issue production tokens from Keycloak for each application you switch, without deleting Auth0.
- Pause signups or plan a last delta export.
- Import the final user file into the production realm.
- Repeat the one-user password test.
- Change one application's issuer, client id, and secret.
- Leave Auth0 in place for the applications you have not switched.
Proof to capture: The switched application accepts a Keycloak login, and the Auth0 tenant still has the pre-cutover export on disk.
Rollback
Point a switched application back at Auth0.
- Stop new signups on Keycloak.
- Restore the application's Auth0 client settings.
- Export any user who signed up or changed a password only in Keycloak.
- Decide how that person gets back into Auth0. A Keycloak hash is not automatically an Auth0 hash.
- Confirm the application issues Auth0 tokens again.
Proof to capture: The application verifies Auth0 tokens, and Keycloak-only accounts are listed.
- The known-user password test fails on the production realm
- A required token claim is missing
- A social or enterprise connection fails
- MFA that you promised to keep is not accepted
Prove the migration worked.
Every blocking check must pass. Capture the evidence before cleanup begins.
| Pass | ID | Check | Method | Expected result | Evidence |
|---|---|---|---|---|---|
V-01Blocking | User counts | Compare the export job with the Keycloak user count for that realm. | The scoped users are present, including blocked users in the state you chose. | Count sheet | |
V-02Blocking | Known-user login | Sign in as a user whose current password you know. | Keycloak accepts it, or the reset path you chose works. | Login note | |
V-03Blocking | Old ids | Look up a user by the stored Auth0 id. | The attribute matches the export. | Id sample | |
V-04Blocking | Claims | Call the API with a Keycloak token for each role you care about. | Audience, roles, and custom claims match the Action list. | Token sample | |
V-05Blocking | Social and enterprise | Sign in through each provider. | The account links to the expected user. | Provider checklist | |
V-06Blocking | Factors | Sign in as a user who had MFA. | The factor works, or the user is sent through the enrollment you planned. | MFA note | |
V-07Blocking | Issuer switch | Repeat the login on each switched application. | That app no longer needs Auth0 for the test user. | App checklist | |
V-08Blocking | Reverse the pilot app | Point a non-production app back at Auth0. | It issues Auth0 tokens again. | Rollback note |
Remove the scaffolding safely.
Safe after: Every production application has passed a Keycloak login, and the Auth0 export is stored.
- Archive the NDJSON export and the password-test note. Keep the PGP private key with your secrets process, not in the ticket.
- Remove pilot realms and temporary clients.
- Rotate any client secret that was copied into a ticket.
- Keep the Auth0 tenant until the rollback date.
- Schedule a Keycloak export with nodes stopped, on the cadence you use for realm backups.
Verify against the primary material.
Platform behavior changes. Check these sources and the review dates above before executing a production migration.
- Auth0: bulk export user dataAccessed 2026-11-05
- Auth0: export password hashes and MFA secretsAccessed 2026-11-05
- Keycloak: importing and exporting realmsAccessed 2026-11-05
- Phase Two: Auth0 to Keycloak walkthroughAccessed 2026-11-05
- Skycloak: migrate from Auth0 to KeycloakAccessed 2026-11-05