---
title: "Migrate from Auth0, Keycloak or Clerk"
description: "Move users and passwords to theAuth one login at a time. Import from Auth0, Keycloak, Clerk or Better Auth, run both systems, roll back with one number."
canonical: https://theauth.dev/migrate/
lastmod: 2026-10-10
---

Migration toolkit

# Migrate from Auth0, Keycloak or Clerk without a rewrite.

Keep your current login running. theAuth picks up each user the first time they sign in, you widen a percentage as you gain confidence, and setting it to 0 sends everyone back. Nobody is forced to reset a password on a cutover day.

[Read the migration docs](https://docs.theauth.dev/migrate/) [See the four steps](https://theauth.dev/migrate/#flow)

The strangler flow

## Four steps, no big bang

### Run both

Add your current provider as an external issuer. Agents and MCP clients can use theAuth while people still sign in the old way. [Coexist with your IdP](https://docs.theauth.dev/migrate/coexist-with-your-idp).

### Migrate on login

An onboarding hook creates or links the account after the old login succeeds. It never blocks the login. [Run both and migrate](https://docs.theauth.dev/migrate/run-both-and-migrate).

### Raise the percentage

Rollout is sticky: raising 5 to 20 only adds users. Allowlists and rules go first, and `percent: 0` is the kill switch.

### Retire the old system

Import dormant users, keep their old hashes for lazy migration, then turn off the incumbent login when the status report says everyone active has moved.

Passwords move without a reset. The old hash is checked on first login, then replaced with a theAuth hash while the typed password is in hand. [Lazy password migration](https://docs.theauth.dev/migrate/lazy-passwords).

Dry run first

## Plan before you write anything

plan reads your export and changes nothing. It tells you which hash formats you have and who would reset. import is a dry run until you add --apply, and running it twice changes nothing the second time. Reports hold counts and error codes, never emails, names or hashes.

terminal

```text
# what would happen? reads the export, touches no database
theauth migrate plan --from keycloak ./export

# write it, then compare counts
theauth migrate import --from keycloak ./export --db ./theauth.db --apply
theauth migrate verify --from keycloak ./export --db ./theauth.db --sample-email someone@yourcompany.com
theauth migrate status --db ./theauth.db
```

Supported sources

## What each source gives you

Import sources, password hash support and known gaps

| Source | Input | Passwords | Gaps | Docs |
| --- | --- | --- | --- | --- |
| Auth0 | Management API user export (JSON) | bcrypt, only with the hash file Auth0 support gives you. You pass a bcrypt verifier. | Without that file, users reset on first login. | [Auth0 guide](https://docs.theauth.dev/migrate/from-auth0) |
| Keycloak | Realm export | PBKDF2 (SHA-1, SHA-256, SHA-512) built in, kept per user. | OTP and WebAuthn credentials are not imported. | [Import users](https://docs.theauth.dev/migrate/import-users) |
| Clerk | Dashboard CSV or Backend API JSON | bcrypt or argon2 digests, with a verifier you pass. | Other hashers are reported as unsupported. Social connections are not in the export, so users reconnect. | [Clerk guide](https://docs.theauth.dev/migrate/from-clerk) |
| Better Auth | Dump of the user and account tables | scrypt built in, including its salt:key layout. | Check one real login with `migrate verify` before trusting the batch. | [Better Auth guide](https://docs.theauth.dev/migrate/from-better-auth) |
| Auth.js | Adapter tables (users, accounts) | Only if your Credentials provider keeps a bcrypt column. | Sessions are not imported. Users sign in once more. | [Import users](https://docs.theauth.dev/migrate/import-users) |
| CSV or JSON | Any file, with a column map | bcrypt and argon2 by prefix. | Other hashes are listed as unsupported and the user resets. | [Import users](https://docs.theauth.dev/migrate/import-users) |
| Firebase | Not supported | Firebase scrypt needs your signer key and parameters. | Those users reset their password. | [Pick a path](https://docs.theauth.dev/migrate/choose-a-path) |

There is no Keycloak-specific guide yet. For Keycloak, read [Import users](https://docs.theauth.dev/migrate/import-users) and [Pick a migration path](https://docs.theauth.dev/migrate/choose-a-path).

Be honest with yourself

## What you give up and known gaps

- bcrypt and argon2 are not bundled. You pass a verifier such as bcryptjs. Without one, those users reset on first login.
- Firebase scrypt is not supported. Those users reset their password.
- The theauth migrate CLI works with SQLite. For Postgres or MySQL, call importUsers from a script with your own migration store.
- Keycloak OTP and WebAuthn credentials are not imported, so users enroll again.
- Clerk exports carry no social connections. Users reconnect on their first social sign-in.
- Sessions and tokens issued by theAuth stay valid until they expire after a rollback. Revoke them if you need them gone.

Rollback

Set percent to 0 and every user and route goes back to the incumbent on the next request. It overrides the allowlist, rules and per-route cutover. Test the switch in staging before you need it. See [Pick a migration path](https://docs.theauth.dev/migrate/choose-a-path) for how each path undoes.

Next

## Pick your path

Start with the guide that matches how much risk you can take. Compare how theAuth differs from your current provider on the [compare pages](https://theauth.dev/compare/), or read the [full migration docs](https://docs.theauth.dev/migrate/).

- [Pick a migration path](https://docs.theauth.dev/migrate/choose-a-path)
- [Run both and migrate](https://docs.theauth.dev/migrate/run-both-and-migrate)
- [Import users](https://docs.theauth.dev/migrate/import-users)
