Migrating from Auth0 to Keycloak: A Step-by-Step Guide
A practical guide to migrating your identity stack from Auth0 to Keycloak. Covers user migration, social login re-linking, session continuity, and common pitfalls.
KeycloakPro Team
KeycloakPro Team
Why Companies Are Leaving Auth0
Since Okta acquired Auth0 in 2021, the landscape has shifted. Pricing restructuring removed affordable tiers, the October 2023 support system breach affected all customers, and MAU-based billing has made costs unpredictable for growing companies.
If you're reading this, you've probably already decided to move. This guide will show you how to do it safely, with zero downtime and no user disruption.
Migration Overview
A successful Auth0 to Keycloak migration has four phases:
- Prepare — Set up Keycloak, map your Auth0 configuration
- Migrate Users — Export users, import into Keycloak
- Migrate Applications — Update your apps to point at Keycloak
- Cutover — Switch DNS, validate, decommission Auth0
The typical timeline is 2-4 weeks depending on complexity.
Phase 1: Prepare Your Keycloak Environment
Set Up Keycloak
Deploy Keycloak 26.x on your preferred infrastructure. For production, we recommend:
# Using Docker for local testing
docker run -p 8080:8080 \
-e KC_BOOTSTRAP_ADMIN_USERNAME=admin \
-e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:26.0.0 start-dev
For production, deploy on Kubernetes with PostgreSQL. See our HA Cluster guide for details.
Map Auth0 Concepts to Keycloak
| Auth0 Concept | Keycloak Equivalent |
|---|---|
| Tenant | Realm |
| Application | Client |
| Connection | Identity Provider or User Federation |
| Rule / Action | Authentication Flow / SPI |
| Organization | Organization (Keycloak 24+) |
| Role | Realm Role or Client Role |
| Permission | Authorization Scope |
| Universal Login | Keycloak Theme |
| Custom Domain | Frontend URL Configuration |
Export Your Auth0 Configuration
Before migrating, document everything:
- Applications: List all clients, their types (SPA, Regular Web, M2M), callback URLs, and allowed origins
- Connections: Social providers (Google, GitHub, etc.), enterprise connections (SAML, OIDC), database connections
- Rules/Actions: Custom logic that runs during authentication
- Roles & Permissions: RBAC configuration
- Branding: Universal Login customization, email templates
Phase 2: Migrate Users
This is the most critical phase. Auth0 stores password hashes using bcrypt, which Keycloak supports natively.
Export Users from Auth0
Use the Auth0 Management API to export users:
# Create an export job
curl --request POST \
--url 'https://YOUR_DOMAIN.auth0.com/api/v2/jobs/users-exports' \
--header 'authorization: Bearer YOUR_TOKEN' \
--header 'content-type: application/json' \
--data '{
"format": "json",
"fields": [
{"name": "user_id"},
{"name": "email"},
{"name": "email_verified"},
{"name": "name"},
{"name": "given_name"},
{"name": "family_name"},
{"name": "identities"},
{"name": "created_at"},
{"name": "last_login"}
]
}'
Handle Password Hashes
Auth0 uses bcrypt for password hashing. Keycloak supports bcrypt through a credential provider. The migration script needs to:
- Extract the bcrypt hash from Auth0's export
- Create the user in Keycloak with the hash preserved
- Users can log in with their existing password — no reset needed
// Keycloak user representation with imported bcrypt hash
{
"username": "user@example.com",
"email": "user@example.com",
"emailVerified": true,
"enabled": true,
"firstName": "Jane",
"lastName": "Smith",
"credentials": [
{
"type": "password",
"credentialData": "{\"hashIterations\":10,\"algorithm\":\"bcrypt\"}",
"secretData": "{\"value\":\"$2a$10$...the_bcrypt_hash...\"}"
}
]
}
Import Users into Keycloak
Use the Keycloak Admin REST API for bulk import:
# Import a single user
curl --request POST \
--url 'http://localhost:8080/admin/realms/YOUR_REALM/users' \
--header 'authorization: Bearer ADMIN_TOKEN' \
--header 'content-type: application/json' \
--data '@user.json'
For large user bases (50,000+), use Keycloak's partial import feature or a custom migration script that batches requests and handles rate limiting.
Migrate Social Login Identities
Users who signed up via Google, GitHub, or other social providers need their identity links preserved. In Keycloak, these are called federated identity links:
# Link a social identity to an existing Keycloak user
curl --request POST \
--url 'http://localhost:8080/admin/realms/YOUR_REALM/users/USER_ID/federated-identity/google' \
--header 'authorization: Bearer ADMIN_TOKEN' \
--header 'content-type: application/json' \
--data '{
"identityProvider": "google",
"userId": "google-user-id-from-auth0",
"userName": "user@gmail.com"
}'
This ensures users who signed up with "Sign in with Google" on Auth0 can continue using Google login on Keycloak without creating a new account.
Phase 3: Migrate Applications
Update OIDC Configuration
For most applications, migration means updating the OIDC/OAuth2 configuration to point at Keycloak instead of Auth0:
Before (Auth0):
ISSUER=https://your-tenant.auth0.com/
CLIENT_ID=auth0_client_id
CLIENT_SECRET=auth0_client_secret
After (Keycloak):
ISSUER=https://keycloak.yourdomain.com/realms/your-realm
CLIENT_ID=keycloak_client_id
CLIENT_SECRET=keycloak_client_secret
Handle Token Differences
Auth0 and Keycloak tokens have different claim structures. Key differences:
| Claim | Auth0 | Keycloak |
|---|---|---|
| User ID | sub (auth0 pipe user_id) | sub (UUID) |
email | email | |
| Roles | https://your-ns/roles (custom) | realm_access.roles |
| Permissions | permissions (custom) | resource_access.{client}.roles |
| Organization | org_id | organization (with Orgs enabled) |
You'll need to update your application code to read claims from the new locations. The cleanest approach is to create a token mapper in Keycloak that adds claims in your existing format, so your application code doesn't change.
Migrate Auth0 Rules/Actions to Keycloak Flows
Auth0 Rules and Actions map to Keycloak Authentication Flows and Protocol Mappers:
- Post-login enrichment (adding custom claims) → Protocol Mapper or Script Mapper
- Conditional MFA → Conditional Authentication Flow
- IP allowlisting → Custom Authenticator SPI
- User metadata sync → Event Listener SPI
Phase 4: Cutover
The Zero-Downtime Strategy
- Run both systems in parallel — Keycloak handles new logins, Auth0 is still available as fallback
- Gradual rollout — Route 10% of traffic to Keycloak, monitor for errors, increase to 25%, 50%, 100%
- Session bridge — Users with active Auth0 sessions are seamlessly redirected to Keycloak on their next login
- DNS cutover — Once 100% of traffic is on Keycloak, update DNS and decommission Auth0
Validation Checklist
Before cutting over completely, verify:
- All users can log in with email/password
- Social login (Google, GitHub, etc.) works correctly
- MFA enrollment and verification works
- Token claims match what your applications expect
- Session timeout and refresh token behavior is correct
- Password reset flow works end-to-end
- New user registration works
- Rate limiting and brute-force protection are configured
- Monitoring and alerting are in place
Common Pitfalls
1. Forgetting to Migrate Password Hashes
If you create users without their password hashes, every user will need to reset their password. This is the number one mistake in Auth0 migrations. Always use the bcrypt hash import method described above.
2. Breaking Social Login
Social login requires matching the external user ID exactly. If the Google user ID in Keycloak doesn't match what Auth0 stored, users will be created as new accounts. Always import federated identity links.
3. Ignoring Token Claim Differences
Your applications depend on specific token claims. Don't assume Keycloak tokens look like Auth0 tokens. Map claims explicitly using Protocol Mappers and test every application.
4. Not Testing the Rollback Plan
Always have a rollback plan. Keep Auth0 active until you're confident Keycloak is stable. A typical safe decommission timeline is 30 days after full cutover.
Timeline Estimate
| Phase | Duration | Dependencies |
|---|---|---|
| Prepare Keycloak | 2-3 days | Infrastructure access |
| Migrate Users | 1-3 days | Auth0 Management API access |
| Migrate Applications | 3-7 days | Application deployment access |
| Parallel Running | 1-2 weeks | Monitoring in place |
| Full Cutover | 1 day | Stakeholder sign-off |
Total: 2-4 weeks for a typical migration with 10,000-100,000 users.
What You'll Save
For a SaaS platform with 50,000 MAU:
- Auth0 Enterprise: ~$80,000 - $120,000/year
- Keycloak on AWS (HA): ~$12,000 - $18,000/year
- Annual savings: $62,000 - $108,000
That's money back in your engineering budget, every year, forever. And you own your identity infrastructure — no vendor lock-in, no surprise pricing changes, no dependency on a third party's security posture.
Need Help With Your Migration?
We've migrated dozens of companies from Auth0 to Keycloak — from startups with 5,000 users to enterprises with 500,000+. Every migration includes user import, social login re-linking, application updates, and a 30-day warranty.
Get a free migration assessment — we'll review your Auth0 setup and give you a fixed-price quote within 48 hours.
Need Help With Keycloak?
Our team specializes in production-grade Keycloak deployments. Get a free 30-minute strategy consultation.
Book a Free Strategy Call