Skip to main content

Migrating to LumoAuth

LumoAuth ships a one-command migration path for Auth0 (lumo migrate auth0), plus guided manual migrations for Clerk, Okta, Cognito, and Firebase that use the Admin API directly. Each guide explains:

  • What gets migrated (users, organizations, groups, roles, SSO connections)
  • What gets dropped and why (passwords, vendor-specific session state, MFA enrolment)
  • How to do the migration with zero downtime (parallel-run pattern)

Pick your source platform​

FromGuideMethod
Auth0Migrating from Auth0lumo migrate auth0 --file users.json
ClerkMigrating from ClerkExport, reshape with jq, create users through the Admin API
OktaMigrating from OktaExport, reshape with jq, create users through the Admin API; or keep Okta as the upstream identity provider
AWS CognitoMigrating from CognitoExport with the AWS CLI, reshape with jq, create users through the Admin API
Firebase AuthMigrating from FirebaseExport with the Firebase CLI, reshape with jq, create users through the Admin API

The manual guides all use the same endpoint the Auth0 importer calls, POST /orgs/{orgId}/api/v1/admin/users, one user per request. Call it with curl, with lumo api POST /users --data '{…}', or use lumo users create for its flag-based subset (--email, --name, --given-name, --family-name, --username, --password, --phone, --roles, --groups, --verified).

What every migration preserves​

Every guide carries over:

  • The user's email, email verification state and name fields
  • Group / organization memberships (for sources that have them)

The Admin API's create endpoint stores email, username, name, givenName, familyName, phoneNumber, password, isActive, emailVerified, roles and groups. It accepts a metadata object as well, but user responses do not return it, so do not rely on it to carry the vendor's user id. Instead, keep your own mapping from the vendor id (auth0|abc123, user_2abc…, 00u1abc…) to the LumoAuth user id returned in the create response (data.id); each guide's import loop records it. App code that hard-coded the old id looks the user up through that table.

note

LumoAuth assigns each migrated user a fresh createdAt at import time; the create endpoint does not accept a caller-supplied creation timestamp. Keep the vendor's original timestamp in your own mapping table if your app relies on it.

What every migration drops​

  • Password hashes. bcrypt costs, peppers, and breach-check flags don't survive the migration cleanly. Migrated users go through your organization's first-login flow (magic link / password reset / SSO).
  • Active session state. Old refresh tokens are not honored — users sign in fresh.
  • Vendor-specific MFA enrolment. TOTP seeds (authenticator-app secrets) and passkeys are bound to the source vendor's domain; new enrolment is required on LumoAuth. With the default Risk-based requirement users re-enroll from Sign-in & security; set the MFA policy to Optional to invite them after every sign-in, or Required with a grace period to make it mandatory (see MFA).

Parallel-run pattern (zero-downtime)​

For production migrations, run both providers side-by-side until you've cut over:

  1. Replicate users. For Auth0, run lumo migrate auth0 --file users.json against an export — idempotent, so it's re-runnable as more users sign up on the source. For Clerk, Okta, Cognito, and Firebase, follow that guide's import loop (same idempotent, re-runnable behavior: a 409 Conflict means the user already exists).
  2. Dual-issue tokens. Your app accepts tokens from either provider. Tag each user with migration_source in your own database so audit logs make sense.
  3. Migrate logins. When a user signs in on the source, prompt them to sign in to LumoAuth (magic link). Once they have, mark migrated_to_lumoauth=true on your user record.
  4. Cut over. When ≥ 95% of monthly-active users have migrated, flip the default to LumoAuth. The remaining 5% migrate on next sign-in.
  5. Sunset the source. After 90 days of no traffic, decommission.

Migration support​

Migrations of more than 10K users? Email migrate@lumoauth.dev. We'll dry-run your export, surface any data-shape issues, and pair on the cutover.