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 concept | VEREID equivalent |
|---|---|
| Tenant | Tenant (developer.vereid.com) |
| Application | OAuth 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) |
| Action | Hook (Lambda) |
| Custom claim via Action | Configured claim mapping |
| Universal Login | Hosted Login (auth.vereid.com) |
| Custom domain | Custom domain wizard |
| Branding | Theme tokens at runtime |
| Log streams | Webhook subscription on oauth.* events |
| User search | Admin 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_idImported 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:
| Auth0 | VEREID |
|---|---|
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, notsetCustomClaim. - 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:verificationYour 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:
- Add
auth.example.comindeveloper.vereid.com → Domains. - Add the printed CNAME to your DNS.
- Wait for ACM cert issuance (typically under 5 minutes).
- Update your SPA's
issuertohttps://auth.example.com. - 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.