Migration Strategy

A migration to Descope moves four things: your data (tenants, SSO connections, roles, users, and applications), your passwords, your login experience, and the traffic from each of your apps. This page describes the order that gets larger organizations to production fastest, and the decisions you make at each stage.

This page is for teams that plan a production migration across several apps or many customer tenants. If you want the exact export and import steps for one provider, go to that provider's guide from the migration overview.

Match First, Then Enhance

The fastest migrations start with a Descope setup that behaves exactly like your current auth. Users sign in with the same methods, see the same screens, and land in the same tenant with the same roles. New features such as passkeys, adaptive MFA, or a redesigned login page come after the cutover.

A 1:1 match gives you a simple test for every app: does the app behave the same as before? When the answer is yes for every login path, the app is ready to move. When you change the experience during the migration, a failed test can come from the migration or from the new feature, and the two are hard to separate.

After every app runs on Descope, you can improve the experience one change at a time, with the old behavior as a known baseline.

Choose Your Path

Your current setup decides which steps apply to you. Most organizations fit one of three shapes, and many have a mix of them.

  • Homegrown auth: You own the user store, so you can export all of your users, tenants, roles, and SSO connections. You import them into Descope, and then move each app to Descope.
  • A hosted provider with embedded login: Your apps call a provider such as Auth0, Cognito, or Firebase through its SDK. You import your data, rebuild the login screens as Flows, and then replace the provider's SDK with the Descope SDK in each app.
  • A hosted provider with federated apps: Your apps connect to a provider such as Okta Customer Identity, Auth0, or PingOne over OIDC or SAML. Descope can act as an identity broker between your apps and that provider, which lets you move one app at a time.

If your customers sign in through their own identity providers (IdPs), such as Okta Workforce or Microsoft Entra ID, you also need SSO migration. SSO migration lets those customers keep their current IdP configuration, so their IT teams do not have to change anything.

In every case, you migrate apps one at a time rather than all at once. A per-app cutover keeps each change small, makes each test clear, and limits the effect of a problem to one app.

Step 1: Plan the Mapping

Before you import anything, decide how each object in your current system maps to Descope. For example, an Auth0 Organization becomes a Descope tenant, and an Auth0 Action usually becomes a step in a Flow. The mapping also tells you which data you can export, and which data you must rebuild.

You have three ways to produce the mapping:

  • With an AI agent: The Descope Skills include migration skills for Auth0, Okta Customer Identity, Stytch, PingOne, and WorkOS. With the Descope MCP Server connected, a skill reads your code and your current configuration and writes a migration plan for you to review before it changes any code. For a homegrown system or a provider without a skill, the agent can still read your configuration through the MCP server and explain how each piece maps to Descope.
  • With Descope Support: The Descope team can review your current setup and help you plan the migration. Contact Descope Support to start.
  • On your own: If your team already knows identity well, you can use the provider guides on this site to configure Descope directly.

Step 2: Import Your Data

Import your data in dependency order, because each object can refer to objects that come before it. A user can belong to a tenant and hold roles, and an application can refer to users. If you import users first, their tenant and role assignments have nothing to point to.

The fastest way to move your data is to let an AI agent write the migration scripts for you. An agent connected to the Descope MCP Server can write a script that exports your data from your current provider or homegrown database. The agent then maps the export to Descope and writes the import scripts, which you review and run with a Management Key.

An agent writes the script for your exact data, including custom attributes and edge cases that a generic tool does not know about. Scripts are easy to rerun, so you can import a test batch into a development project first.

If you prefer not to use an AI agent, Descope publishes open-source migration scripts for several providers, such as the Descope migration tool for Auth0, Cognito, Firebase, and Ping. You can clone these scripts and run them as they are, or use them as templates for your own scripts. The Auth0, Cognito, Firebase, Ping, Shopify, and Custom Data Store guides link to their scripts.

Use this order:

  1. Tenants: Create one tenant for each customer organization.
  2. SSO connections: Add each customer's SAML or OIDC settings to its tenant. See SSO migration for how to keep the customer's current IdP configuration.
  3. Roles and permissions: Recreate your roles and permissions, or your ReBAC schema if you use fine-grained authorization.
  4. Resources: Create a Resource for each API that your current provider issues tokens for, with the same audience and scopes. See Machine-to-Machine Clients and APIs.
  5. Users: Import users with their tenant memberships, roles, and custom attributes through the User Management API.
  6. Applications: Recreate federated apps, and import OAuth clients with their existing client IDs and secrets.

Passwords

Your password strategy depends on whether your current provider lets you export password hashes.

If you can export the hashes, import them with the users. Descope supports common hash formats, so users keep their current passwords and do not see a reset. The migration overview lists the supported algorithms.

If you cannot export the hashes, use just-in-time (JIT) migration. Your sign-in Flow validates the password with your legacy provider, such as Okta, Entra ID, or Cognito, through a Generic HTTP connector.

If the password is correct, the Flow creates the user in Descope with that password. The user signs in as usual and never notices the migration.

Each user migrates on their next sign-in, so users who never sign in stay behind.

Plan a date to import the remaining users without passwords, send them a password reset or passwordless sign-in, and turn off the legacy provider.

Passkeys, Authenticator Apps, and Saved Passwords

Passwords are not the only credentials your users hold. Passkeys, authenticator app (TOTP) seeds, and the passwords that browsers save for your sign-in page each behave differently in a migration.

  • Saved passwords: Browsers and password managers save a password for the domain where the user typed it. If your sign-in page moves to a new hostname, such as auth.example.com instead of login.example.com, the saved password no longer fills in automatically. Users can still sign in, but they have to find the saved entry or type the password. Embedded Flows that run on your app's own pages keep the same domain, so autofill keeps working there.
  • Passkeys: A passkey belongs to the domain where the user registered it. You can migrate passkeys only if your current provider lets you export them. Descope's passkey top-level domain must also match the domain from registration. Contact Descope Support to import exported passkeys.
  • Authenticator apps: If your current provider exports TOTP seeds, you can import them with the users. Users then keep using their existing authenticator app.

What you can export depends on the provider. Auth0 exports password hashes and MFA secrets through a support request, as a PGP-encrypted file.

ProviderPassword hashesPasskeysTOTP seeds
Auth0YesYesYes
AWS CognitoNoNoNo
Okta CISNoNoNo
Azure AD B2CNoNoNo

When a credential cannot move, users re-enroll it in Descope. A common pattern is to mark imported users with a freshlyMigrated attribute. Your sign-in Flow then prompts those users to register a new passkey or authenticator app after their first sign-in.

Machine-to-Machine Clients and APIs

Users are not the only callers of your APIs. Backend services, scheduled jobs, and partner integrations often authenticate as machine-to-machine (M2M) clients, for example an Auth0 M2M application that uses the client_credentials grant. These clients hold a client ID and secret from your current provider, and your APIs validate the tokens that the provider issues to them.

In Descope, the client becomes a confidential Inbound App, and the API it calls becomes a Resource. The Resource defines the API's audience (aud) and scopes, and Policies decide which scopes each client receives.

Resources matter most for M2M clients. A client_credentials token has no user and no consent screen behind it, so the Resource's scopes are the only limit on what the client can do.

To move your M2M clients, you can follow these steps:

Create a Resource for each API

Create an API Resource for each API your current provider protects, such as the APIs in your Auth0 tenant. Use the same audience and scope names, so your APIs keep accepting the same claims, for both M2M and user tokens.

Import each client with its existing credentials

Create an Inbound App for each client, and pass its current clientId and clientSecret. The client keeps calling with the same credentials. See Migrating OAuth Clients.

Associate the clients with their Resources

Associate each Inbound App with the Resources it calls. Then add Policies that grant each client only the scopes it had before.

Update the issuer in your APIs

Point each API's token validation at the Descope issuer. Importing a custom client ID changes the issuer, as described in Issuer After Importing Client IDs.

When Your Current System Has No Resources

Some systems never used OAuth for service calls. Services may share a static API key, or call internal APIs that never validate an audience or scopes. In that case, you have nothing to match 1:1, and Resources become a design decision instead of a migration step.

Descope recommends that you treat Resources as a follow-up for these systems. Migrate your users and apps first, and keep your current service authentication unchanged during the cutover. If a service needs a Descope-issued token right away, a Descope Access Key is the closest match to a static API key.

After the migration, you can define a Resource for each internal API and move each service to an Inbound App with the client_credentials grant. With that change, every service token carries an audience and scopes that your APIs can validate. Each service gets only the access you grant it, instead of a shared key with full access.

Step 3: Rebuild the Login Experience

Descope recommends Flows for your login experience, because you can change a Flow's logic and screens without a code deploy.

You can build each Flow in the Console, or ask an AI agent connected to the Descope MCP Server to rebuild your current login. The agent can also apply your styles and set up widgets, such as the User Profile Widget, to replace your app's account pages.

What you do next depends on how each app connects to your auth today.

Embedded Login

If an app shows the login screens inside its own pages, make sure the new Flow matches the current login experience screen for screen. Then replace the old login component with the Descope Flow component in that app. The SDK guides show how to add a Flow to each framework.

Federated Apps

If an app connects to your current provider over OIDC or SAML, Descope can act as an identity broker. In a broker setup, Descope sits between your apps and your legacy provider. Each app connects to Descope as a federated app, and a step in your Flow sends each user to the right place:

  • A user from a customer that uses SSO goes through that tenant's SSO connection.
  • A user who still lives in the legacy provider goes to the legacy provider, which you add to Descope as an OIDC or SAML connection.
  • Every other user signs in with Descope directly.

Your apps

Customer portal
OIDC
Admin console
SAML
Mobile app
OIDC

Where users sign in

Your apps connect only to Descope, over OIDC or SAML. A step in your Flow decides where each user signs in. As you migrate users and customers, more of them move to Descope Flows, and your apps never change again.

With a broker in place, your apps talk only to Descope. You can then move users and SSO customers off the legacy provider at your own pace, without another change to the apps.

Step 4: Cut Over to Production

Before you cut over any app, make sure your automated tests can sign in through Descope. See Get Automated Tests Running First.

How you cut over depends on who controls the hostname that your customers' IdPs send SSO responses to. Each customer configured that hostname in their SAML or OIDC connection, so the hostname decides how much you can change without asking customers to change anything.

If You Manage Your Own Auth Hostname

With homegrown auth, you usually own the hostname in your customers' IdP configuration, such as login.example.com. Steps 1 to 3 are usually enough.

Point that hostname to Descope, and Descope routes each SSO response to the correct tenant. The SSO migration guide describes the DNS redirect.

If a Hosted Provider Holds Your Connections

If your apps and customer connections live in a provider such as Auth0, Okta Customer Identity, PingOne, or WorkOS, that provider serves the hostname your customers configured.

You move in two phases. First, route every app through Descope while Descope federates to the provider. Then, move the existing hostname to Descope.

Your apps
Flows or Federated Apps
auth.example.comNew hostname
Descope
Identity broker
Federation
Legacy provider
Auth0, Okta, WorkOS
login.example.comExisting hostname
Customer IdPs
SAML and OIDC

Each app moves to Descope on a new hostname, one at a time. Descope federates SSO users to the legacy provider, which still holds the customer connections, so no customer changes anything yet.

Phase 1: Route All Apps Through Descope

In the first phase, every app starts to use Descope, either through embedded Flows or as a Federated App. The legacy provider stays in place and still holds the customer connections.

  1. Create a new hostname for Descope: Set up a new custom domain for Descope, such as auth.example.com. Keep the existing hostname on the legacy provider for now.
  2. Federate to the legacy provider: Add the legacy provider to Descope as an OIDC or SAML connection. Use a Flow action to send SSO users to the provider, which signs them in through the customer's existing connection.
  3. Move each app to Descope: Move one app at a time to the new hostname. Test each app on Descope before you move the next one.

At the end of Phase 1, all sign-in traffic flows through Descope. Your apps no longer talk to the legacy provider directly, so the next phase changes nothing in your apps.

Phase 2: Move the Existing Hostname

After every app runs on Descope, you point the existing hostname, such as login.example.com, to Descope. The SSO responses that customer IdPs send to that hostname now reach Descope. SSO migration then takes over each connection, so customers do not have to change their SAML or OIDC settings.

When the hostname points to Descope, you can stop federating to the legacy provider and turn it off.

The existing hostname must be one you control

Phase 2 works only if your customers configured a custom domain that you own, such as login.example.com. If a customer configured the provider's own domain, such as your-tenant.auth0.com, you cannot point that hostname to Descope. Those customers must update their connection, which they can do themselves with the SSO Setup Suite.

A two-phase cutover lets you test every app on its own and move gradually, with very little downtime. If a problem appears in Phase 1, it affects only the app you just moved.

Sessions

Users with an active session when an app moves do not have to sign in again if you add session migration. With session migration, your app sends the legacy Auth0 or Okta token to Descope, and Descope exchanges it for a Descope session.

Session migration can also create users. In just-in-time mode, Descope creates a user who is not in Descope yet from the provider's profile. For an Okta or Auth0 migration, session migration can then replace part of the bulk import for users with an active session at cutover.

Test Each App Before It Moves

Because each app moves on its own, you can test each one against the same list before it goes to production. Use a separate environment for testing, and test users for automated tests.

Get Automated Tests Running First

Make sure your automated test suites can sign in through Descope before you migrate your first app. When many apps move in sequence, a test suite that cannot authenticate blocks every app behind it. Migrations commonly stall at this step, because the accounts that tests use are often not part of the main user import.

Before the first cutover, go through every account that your tests and pipelines use to sign in:

  • Service accounts: If your tests or CI pipelines call your APIs as an M2M client, import that client as an Inbound App with its existing client ID and secret. Associate the Inbound App with the same Resources as in production. See Migrating OAuth Clients.
  • Passwordless test users: For end-to-end tests that sign in through OTP, magic links, or enchanted links, create test users in Descope. Your tests can generate codes and link tokens for test users through the API, so Descope sends no email or SMS.
  • Automation users with passwords: If a test signs in with a password, that user must already exist in Descope with the password. You can import the user with their password hash, or make sure your JIT migration Flow can migrate them on the first test run. Otherwise, the first automated sign-in fails.

Run the full test suite against Descope in your test environment and resolve any failures before you start the cutover. With the tests in place, each later app only needs its own app-specific tests.

Checklist for Each App

For each app, test that:

  • Every sign-in method from the old setup works, including password, social login, MFA, and SSO.
  • Users land in the correct tenant with the correct roles and permissions.
  • Tokens contain the claims that the app and its APIs expect.
  • Sign-out, password reset, and account recovery work.
  • Any federated or OAuth clients receive tokens from the new issuer.

When an app passes every item, move it to production and start on the next app. Before the final cutover, go through the production checklist.

Next Steps

Was this helpful?

On this page