Skip to Content
GuidesMigrating from Auth0

Migrating from Auth0

Auris provides feature parity with Auth0 across authentication, authorization, and user management, plus capabilities that Auth0 charges extra for or does not offer (Zanzibar-style FGA, built-in SCIM provisioning, Actions Engine with visual editor, and self-hosted deployment). This guide walks you through a complete migration from Auth0 to Auris with minimal downtime.

Feature Mapping

The following table maps Auth0 features to their Auris equivalents:

Auth0 FeatureAuris EquivalentNotes
Universal LoginHosted Login PagesOAuth2 Authorization Code + PKCE, tenant-branded
Rules / ActionsActions EngineSandboxed JavaScript, 6 trigger points, visual Blueprint editor
RBAC (Roles + Permissions)Roles & Permissions V2Tri-state ALLOW/DENY, per-application scoping
OrganizationsOrganizations B2BMulti-org with 4 member roles, token-based invitations
Auth0 FGA (OpenFGA)Auris FGAZanzibar-style ReBAC, OpenFGA-compatible DSL
Social ConnectionsSocial Login9 providers (Google, GitHub, Microsoft, Apple, Facebook, Discord, LinkedIn, Twitter/X, Slack)
Enterprise Connections (SAML/OIDC)Enterprise SSOSAML 2.0 + OIDC via Keycloak IdP brokering, domain verification
Machine-to-MachineClient CredentialsOAuth2 client_credentials grant, scope-based, JWT with type: 'm2m'
Hooks / WebhooksWebhooksHMAC-SHA256 signed, retry with exponential backoff
Custom ClaimsCustom JWT ClaimsPer-application, 5 value types (static, user attribute, role-based, expression)
MFAMulti-Factor AuthTOTP, SMS OTP, WebAuthn/Passkeys, adaptive MFA with risk scoring
Passwordless (Email)Magic LinksToken-based email login with auto-signup
Passwordless (SMS)SMS OTPTwilio provider, rate-limited with cooldown
Attack ProtectionAttack ProtectionIP rules, brute-force lockout, CAPTCHA (Turnstile/hCaptcha/reCAPTCHA), suspicious login detection
Log StreamingLog StreamingWebhook, S3, Datadog, Splunk
User Import/ExportUser Import/ExportCSV and JSON, async processing with progress tracking
SCIMSCIM 2.0 ProvisioningRFC 7644 compliant, attribute mapping, bulk operations
Custom DomainsCustom DomainsWhite-label auth pages, automatic SSL
Rate LimitingRate Limiting4 tiers, sliding window, standard headers
BrandingBrandingLogo, colors, favicon, company name

Migration Steps

Step 1: Export Users from Auth0

Use the Auth0 Management API to export your users. You can use the Auth0 Dashboard (User Management > Import/Export) or the API directly:

# Create an export job curl -X POST https://YOUR_AUTH0_DOMAIN/api/v2/jobs/users-exports \ -H "Authorization: Bearer $AUTH0_MANAGEMENT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "format": "json", "fields": [ { "name": "user_id" }, { "name": "email" }, { "name": "email_verified" }, { "name": "name" }, { "name": "given_name" }, { "name": "family_name" }, { "name": "created_at" }, { "name": "app_metadata" }, { "name": "user_metadata" } ] }'
# Check export status curl https://YOUR_AUTH0_DOMAIN/api/v2/jobs/JOB_ID \ -H "Authorization: Bearer $AUTH0_MANAGEMENT_TOKEN" # When status is "completed", download the file from the location URL

Auth0 does not export password hashes for users who signed up with email/password. These users will need to reset their password after migration, or you can use the lazy migration pattern described below.

Step 2: Transform and Import Users into Auris

Transform the Auth0 export format to the Auris import format:

// transform-auth0-users.ts import fs from 'fs' interface Auth0User { user_id: string email: string email_verified: boolean name: string given_name: string family_name: string created_at: string app_metadata: Record<string, unknown> user_metadata: Record<string, unknown> } interface AurisImportUser { email: string firstName: string lastName: string emailVerified: boolean // Password is omitted — users will set a new one via password reset } const auth0Users: Auth0User[] = JSON.parse( fs.readFileSync('auth0-export.json', 'utf-8') ) const aurisUsers: AurisImportUser[] = auth0Users.map((user) => ({ email: user.email, firstName: user.given_name || user.name?.split(' ')[0] || '', lastName: user.family_name || user.name?.split(' ').slice(1).join(' ') || '', emailVerified: user.email_verified, })) fs.writeFileSync('auris-import.json', JSON.stringify(aurisUsers, null, 2)) console.log(`Transformed ${aurisUsers.length} users`)

Upload to Auris:

curl -X POST https://auth.yourdomain.com/api/users/import \ -H "Authorization: Bearer $AURIS_ACCESS_TOKEN" \ -H "x-tenant: your-tenant-id" \ -F "[email protected]" \ -F "format=json"

Monitor import progress:

curl https://auth.yourdomain.com/api/users/import/IMPORT_JOB_ID \ -H "Authorization: Bearer $AURIS_ACCESS_TOKEN" \ -H "x-tenant: your-tenant-id"

Step 3: Create Applications in Auris Console

For each Auth0 Application, create a corresponding Application in Auris:

  1. Open Console then Applications then Create Application
  2. Set the Application Type to match the Auth0 application type:
    • Auth0 “Single Page Application” or “Regular Web Application” = Auris WEB
    • Auth0 “Native” = Auris MOBILE
    • Auth0 “Machine to Machine” = Auris M2M
  3. Configure Allowed Callback URLs with the same redirect URIs from Auth0
  4. Configure Allowed Origins with the same origins from Auth0
  5. Note the new Client ID (and Client Secret for M2M apps)

Step 4: Replace the Auth0 SDK with Auris SDK

Install the Auris SDK and remove the Auth0 SDK:

# Remove Auth0 npm uninstall @auth0/auth0-spa-js @auth0/auth0-react @auth0/nextjs-auth0 # Install Auris npm install @auris/js @auris/react # For Next.js: npm install @auris/nextjs

Step 5: Update Your Application Code

The Auris SDK API is intentionally similar to Auth0’s to minimize migration effort.

Provider Setup (React):

// BEFORE (Auth0) import { Auth0Provider } from '@auth0/auth0-react' function App() { return ( <Auth0Provider domain="your-tenant.auth0.com" clientId="auth0-client-id" authorizationParams={{ redirect_uri: window.location.origin + '/callback', }} > <MyApp /> </Auth0Provider> ) } // AFTER (Auris) import { AurisProvider } from '@auris/react' function App() { return ( <AurisProvider domain="auth.yourcompany.com" clientId="auris-client-id" redirectUri={window.location.origin + '/callback'} > <MyApp /> </AurisProvider> ) }

Authentication Hook:

// BEFORE (Auth0) import { useAuth0 } from '@auth0/auth0-react' function Profile() { const { loginWithRedirect, logout, user, isAuthenticated, isLoading, getAccessTokenSilently, } = useAuth0() if (isLoading) return <p>Loading...</p> if (!isAuthenticated) return <button onClick={loginWithRedirect}>Log in</button> return ( <div> <p>Welcome, {user.name}</p> <button onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}> Log out </button> </div> ) } // AFTER (Auris) import { useAuris } from '@auris/react' function Profile() { const { loginWithRedirect, logout, user, isAuthenticated, isLoading, getAccessToken, } = useAuris() if (isLoading) return <p>Loading...</p> if (!isAuthenticated) return <button onClick={loginWithRedirect}>Log in</button> return ( <div> <p>Welcome, {user.name}</p> <button onClick={() => logout({ returnTo: window.location.origin })}> Log out </button> </div> ) }

API Calls with Access Token:

// BEFORE (Auth0) const token = await getAccessTokenSilently() // AFTER (Auris) const token = await getAccessToken() // The rest of your API call code stays the same const response = await fetch('/api/protected', { headers: { Authorization: `Bearer ${token}` }, })

Permission Check (React):

// BEFORE (Auth0 — manual claim check) const { user } = useAuth0() const hasPermission = user?.['https://myapp.com/permissions']?.includes('read:data') // AFTER (Auris — built-in permission hook) import { useCheckPermission } from '@auris/react' const canReadData = useCheckPermission('read:data')

Next.js Middleware:

// BEFORE (Auth0) import { withMiddlewareAuthRequired } from '@auth0/nextjs-auth0/edge' export default withMiddlewareAuthRequired() // AFTER (Auris) import { aurisMiddleware } from '@auris/nextjs/middleware' export default aurisMiddleware({ protectedPaths: ['/dashboard(.*)'], publicPaths: ['/', '/about', '/pricing'], loginUrl: '/auth/login', })

Step 6: Update Redirect URIs

Update the Callback URLs in your Auris application to match what your app sends:

  • Replace https://your-tenant.auth0.com/ with https://auth.yourcompany.com/ in all redirect URIs
  • If you were using Auth0’s default callback path (/api/auth/callback), update it to your Auris callback path

Step 7: Migrate Rules to Actions

Auth0 Rules and Actions map to Auris Actions Engine triggers:

Auth0 TriggerAuris Trigger
post-loginpost-login
pre-user-registrationpre-register
post-user-registrationpost-register
post-change-passwordpost-change-password

Auth0 Action example:

// Auth0 Action (post-login) exports.onExecutePostLogin = async (event, api) => { if (!event.user.email_verified) { api.access.deny('Please verify your email before logging in.') } api.idToken.setCustomClaim('https://myapp.com/role', event.user.app_metadata.role) }

Auris Action equivalent:

// Auris Action (post-login trigger) // Created via Console → Actions → New Action async function action(context) { if (!context.user.emailVerified) { return { deny: true, message: 'Please verify your email before logging in.' } } return { claims: { role: context.user.metadata?.role || 'user' } } }

Create actions in the Console under Actions, or use the API:

curl -X POST https://auth.yourdomain.com/api/actions \ -H "Authorization: Bearer $AURIS_ACCESS_TOKEN" \ -H "x-tenant: your-tenant-id" \ -H "Content-Type: application/json" \ -d '{ "name": "Enforce email verification", "trigger": "post-login", "code": "async function action(context) {\n if (!context.user.emailVerified) {\n return { deny: true, message: \"Please verify your email before logging in.\" }\n }\n return {}\n}", "status": "ACTIVE", "order": 1 }'

Step 8: Migrate RBAC

Export roles and permissions from Auth0 and recreate them in Auris:

# List Auth0 roles curl https://YOUR_AUTH0_DOMAIN/api/v2/roles \ -H "Authorization: Bearer $AUTH0_MANAGEMENT_TOKEN"

For each role, create it in Auris:

curl -X POST https://auth.yourdomain.com/api/roles \ -H "Authorization: Bearer $AURIS_ACCESS_TOKEN" \ -H "x-tenant: your-tenant-id" \ -H "Content-Type: application/json" \ -d '{ "name": "Editor", "description": "Can edit content", "color": "#3B82F6" }'

Then assign permissions to the role using the Auris Console (Roles > [Role] > Permissions) or API. Auris supports tri-state permissions (ALLOW/DENY) which is more granular than Auth0’s binary model.

Step 9: DNS Cutover

Once everything is tested:

  1. Set up a custom domain in Auris (e.g., auth.yourcompany.com)
  2. Update DNS to point your auth domain to Auris
  3. Update all applications to use the new domain
  4. Monitor the Auris audit logs for the first few hours after cutover

Handling Passwords (Lazy Migration)

Since Auth0 does not export password hashes, you have two options:

Option A: Force Password Reset (Simpler)

After importing users, trigger a bulk password reset email:

  1. All imported users receive a “Set your password” email
  2. Users click the link and set a new password on Auris
  3. No code changes required in your application

Option B: Lazy Migration (Zero Friction)

Run Auth0 and Auris in parallel temporarily. When a user logs in:

  1. Auris attempts to authenticate the user
  2. If the user has no password in Auris (imported without one), Auris returns a specific error
  3. Your application catches this error and attempts authentication against Auth0 as a fallback
  4. If Auth0 succeeds, your application creates the password in Auris via the Admin API
  5. Subsequent logins go directly through Auris

This approach migrates passwords transparently as users log in, with zero friction.

The lazy migration pattern requires keeping your Auth0 tenant active during the migration period. Plan to decommission it after a reasonable period (e.g., 30-90 days) when the majority of active users have migrated.

Rollback Plan

If issues arise during migration:

  1. Keep Auth0 active for at least 30 days after cutover
  2. DNS rollback: Point your auth domain back to Auth0 (TTL permitting, this takes effect within minutes to hours)
  3. SDK rollback: Revert the @auris/* packages to @auth0/* in your application code and redeploy
  4. No data loss: Users created in Auris during the migration period can be exported and re-imported into Auth0 if needed

To minimize rollback risk, run both systems in parallel for a testing period before the full DNS cutover.

Post-Migration Checklist

After completing the migration, verify:

  • All users can log in (test with multiple accounts)
  • Social login providers work (Google, GitHub, etc.)
  • MFA enrollment and verification work
  • Role-based access control is enforced correctly
  • Webhooks are delivering events to your endpoints
  • Log streaming is active (if configured)
  • Custom domains and SSL are working
  • Mobile apps (if any) are updated with new SDK
  • M2M applications can obtain tokens
  • SCIM provisioning is connected (if used)