VVEREID Docs
guides

Migrating from Auth0

A pragmatic cutover plan from Auth0 to VEREID Auth — tenant export, rule and action mapping, custom-domain transition, and end-user re-authentication.

Last updated 2026-05-20

This guide walks the end-to-end migration from Auth0 to VEREID Auth. It assumes you are on Auth0 Cloud (universal-login) with a typical SPA + API setup, you are using rules or actions for custom claims, and you want zero downtime for end users.

Why migrate

The headline reason is the vereid_verification custom claim — it lets you trust your users in a way Auth0 cannot, because Auth0 has no upstream identity-verification product. The pricing comparison is also stark at scale (see pricing), but trust beats price for most teams.

What maps cleanly

Auth0 conceptVEREID equivalent
TenantTenant (developer.vereid.com)
ApplicationOAuth App (oauth_clients row)
API (audience)Scope namespace
Connection (DB)Local username/password identity
Connection (Google, Apple, etc.)Social login provider
Rule (deprecated)Hook (Lambda)
ActionHook (Lambda)
Custom claim via ActionConfigured claim mapping
Universal LoginHosted Login (auth.vereid.com)
Custom domainCustom domain wizard
BrandingTheme tokens at runtime
Log streamsWebhook subscription on oauth.* events
User searchAdmin API / console

What does not map

  • Auth0's M2M extension — replaced by standard OAuth 2.0 client-credentials. No tenant-side configuration needed; just register a client with grant_types=["client_credentials"].
  • Auth0 Organisations — VEREID's tenant model has a different shape. If you use Organisations, contact us for a tailored mapping document.
  • Rules (already deprecated by Auth0) — port directly to Hooks.

Step 1 — Export your users

Use Auth0's user export job (POST /api/v2/jobs/users-exports) with connection_id of your database connection. Request fields: user_id, email, email_verified, phone_number, name, nickname, picture, created_at, last_login, and any custom app_metadata you rely on.

You will receive an NDJSON file. Import via:

vereid users import auth0-export.ndjson \
  --map="email=email,name=display_name,nickname=handle,picture=avatar_url" \
  --preserve-id=auth0_user_id

Imported users start with no password. They must complete a one-time password reset on first login — VEREID emails them automatically (template editable in console). This is the safest path: Auth0 does not expose password hashes, so re-hashing is not an option.

Alternatively, if you have hashes from a pre-Auth0 era stored locally, you can import them via vereid users import --hashes=bcrypt. We support bcrypt, argon2id, and scrypt directly.

Step 2 — Recreate apps + scopes

For each Auth0 Application, create a VEREID OAuth App with the same client_id if possible (vereid apps create --client-id=<existing>) so your existing JWT iss change is the only thing your SPA notices. Map your audiences to scopes:

Auth0VEREID
https://api.example.com (audience)api:example (scope namespace)
read:users (scope)api:example/read:users

The colon-separated scope syntax is identical to Auth0's; you mostly do not need to touch your SPA-side requested_scopes.

Step 3 — Port Actions / Rules

For each Action, write a VEREID Hook in Node 20 (Hooks run on Lambda; cold-start is sub-200 ms). The execution context is similar:

// Auth0 Action
exports.onExecutePostLogin = async (event, api) => {
  if (event.user.email.endsWith("@example.com")) {
    api.idToken.setCustomClaim("https://example.com/staff", true);
  }
};
 
// VEREID Hook
export const onPostLogin = async ({ event, api }) => {
  if (event.user.email.endsWith("@example.com")) {
    api.idToken.setClaim("https://example.com/staff", true);
  }
};

Differences:

  • VEREID Hooks are ES modules (export), not CommonJS.
  • The custom-claim helper is setClaim, not setCustomClaim.
  • Hooks must not exceed 500 ms p99. Hard-killed otherwise (you can raise to 2 s on Enterprise).

Step 4 — Wire vereid_verification

Because Auth0 has nothing equivalent, this is the one part of the migration that adds value rather than just preserving the status quo. Add vereid:verification to your requested scopes:

- scope=openid email profile
+ scope=openid email profile vereid:verification

Your id_token now carries the verification claim. You can roll this out to a fraction of users initially via a Hook that conditionally injects the scope.

Step 5 — Custom domain

VEREID supports custom domains on every paid tier. The cutover sequence:

  1. Add auth.example.com in developer.vereid.com → Domains.
  2. Add the printed CNAME to your DNS.
  3. Wait for ACM cert issuance (typically under 5 minutes).
  4. Update your SPA's issuer to https://auth.example.com.
  5. Lower TTL on the old Auth0 custom-domain CNAME to 60 s for the cutover window.

Run both providers in parallel for a week; flip the SPA via feature flag, monitor oauth.token.issued deliveries.

Step 6 — End-user re-authentication

The transition is not silent — Auth0's session cookies are unrecognised by VEREID. End users will see a single re-login prompt. Communicate this to your users before the cutover (the most common operational surprise).

Step 7 — Decommission

Keep Auth0 as the fallback for 30 days after the cutover. If verification.completed deliveries are flowing and your support queue is quiet, archive the Auth0 tenant and revoke the export tokens. We have never seen a customer roll back after the first week.