Migrating user data
In order to migrate your authentication from an existing system to Stytch's B2B SaaS Authentication platform, you will need to import all current organization and user data to Stytch via API or SDK.
Stytch recommends the data migration approaches outlined below. This involves creating a set of jobs to synchronize organization and user data to Stytch.
Dual-write and Backfill
In order to achieve a smooth, zero-downtime migration without any issues around data reconciliation, we recommend setting up dual-writes prior to kicking off a backfill to Stytch. This allows any create, update, or delete requests during the backfill period are reflected in both your current system as well as in Stytch, ensuring that you can cut over to Stytch as the read source of truth without any customer impact or downtime.
However, if you have less than ~500k users and would rather skip the dual write step, you can always run the backfill directly via an Export and Import approach described below.
The above is an example diagram of a Dual-write and Backfill process for users and organizations.
1Set up dual-write on all write paths
For every place you write to your internal member or organization tables, introduce a corresponding write to Stytch. This includes new user signups, user updates, user deletions, organization creations, organization updates and organization deletions.
The returned Stytch member_id or organization_id should be saved in your tables on creation, so you know the user or organization has been migrated.
Organization API endpoints:
- Creations: Create organization via Create Organization
- Updates:
- If the organization doesn't already exist in Stytch, create the organization via Create Organization
- If you already have a stytch_organization_id associated with your record, update the organization via Update Organization
- Deletions: If you've aready created the Organization in Stytch (stytch_organization_id associated with the record) delete the organization via Delete Organization
Member API endpoints:
- Create user:
- If this is a new user joining an existing Organization that has already been migrated to Stytch (stytch_organization_id on record), create via Create Member
- If this is a user signing up for a new Organization or joining an Organization that has not been migrated yet, Create Organization first and store the stytch_organization_id and then Create Member
- Updates:
- If the user doesn't already exist in Stytch, create the user as described above. Use Migrate Member if the user has a password hash in your db.
- If the user already exists (stytch_member_id associated with your record) use the Update Member API for updates to name, email, roles, or metadata.
If the update is to the MFA Phone Number, Password or Member TOTP Registration, you'll need to first delete the old authentication factor record from the Stytch Member, and then call Update Member to complete.
- Deletions: Delete user via Delete Member
2Run a backfill
While dual-write is continuously running, you can assume that all users and organizations in your internal tables without an associated Stytch member_id or organization_id must run through a backfill job that adds them to Stytch via the Create Organization endpoint or the Create Member endpoint, one at a time.
Create Organization:
curl --request POST \
--url https://test.stytch.com/v1/b2b/organizations \
-u 'PROJECT_ID:SECRET' \
-H 'Content-Type: application/json' \
-d '{
"organization_name": "Example Org Inc.",
"organization_slug": "example-org",
"mfa_policy": "REQUIRED_FOR_ALL",
"email_allowed_domains": ["example.com"],
"email_invites": "ALL_ALLOWED",
"email_jit_provisioning": "RESTRICTED",
}'
Create Member:
curl --request POST \
--url https://test.stytch.com/v1/b2b/organizations/{ORGANIZATION_ID}/members \
-u 'PROJECT_ID:SECRET' \
-H 'Content-Type: application/json' \
-d '{
"email_address": "adalovelace@stytch.com",
"mfa_phone_number": "+18000000000",
"mfa_enrolled": true
"trusted_metadata": {"internal_id": "407207d7-2a19-44e8-b192-4e2d45428b31"}
}'
Your backfill job should start with Organizations, then backfill Members once Organizations are complete. This job should submit requests to Stytch at a rate of 100 r/s maximum.
3Move password hashes to Stytch
If your manage passwords in-house within your own databases, you can integrate the logic for migrating passwords hashes into the core dual-write and backfill steps. However, if you are migrating over from a legacy auth provider, like Auth0, that stores password hashes on your behalf, you will need a full data export. In order to minimize the time for drift on password changes, we recommend migrating password hashes at the end of this process by executing a script to call our Migrate Password endpoint for each user after backfill has been completed.
To migrate passwords you will leverage the Migrate Password endpoint by passing in the email_address associated with the Member, and the password hash from your provider.
Stytch offers the option to either allow end users to use the same password across all Organizations they belong to under that email or to scope passwords to the specific Member/Organization. This setting cannot be changed once you have active passwords in your project, so prior to kicking off your migration update your password settings in the Stytch Dashboard to match the password behavior that you would like.
If you want to allow passwords to be used across Organizations, you only need to call the Migrate Password endpoint one time for a given email -- even if the email is associated with multiple Members. If you want passwords to be scoped to the Member/Organization, you will call the Migrate Password endpoint for each MemberID you've migrated to Stytch.
curl --request POST \
--url https://test.stytch.com/v1/b2b/passwords/migrate \
-u 'PROJECT_ID:SECRET' \
-H 'Content-Type: application/json' \
-d '{
"email_address": "adalovelace@stytch.com",
"hash": "$2a$12$vefoDBbzuMb...",
"hash_type": "bcrypt",
"organization_id": "organization-test-07971..."
}'
Export and Import
First, you will need to export your organization and user data from your current auth service. We recommend querying this information from your internal user and organization tables if possible. If you don't have a copy of user and workspace records outside of your auth provider, here are some helpful resources to export from various auth providers:
- To export from Auth0, create a support request.
Next, you will write an import job that calls Stytch's API to create each Organization and Member in Stytch. The logic should resemble the following steps:
1Migrate Stytch Organization
Pass each application user group's name, slug, and authentication settings into Stytch create Organization API endpoint.
- If the Organization has Single Sign-On connections with an identity provider, you will need to create SAML and OIDC connection objects. See Additional migration considerations for more information.
- Configure an Organization's auth settings to control approved authentication methods, allowed email domains, invites, MFA, Just-in-Time (JIT) Provisioning, SSO connections, and more. See the managing Organization settings guide for more information.
curl --request POST \
--url https://test.stytch.com/v1/b2b/organizations \
-u 'PROJECT_ID:SECRET' \
-H 'Content-Type: application/json' \
-d '{
"organization_name": "Example Org Inc.",
"organization_slug": "example-org",
"email_allowed_domains": ["exampleorg.com"],
"email_invites": "RESTRICTED"
}'
2Migrate Stytch Members
For each Stytch Organization a user belongs to, you will need to create a Member object. Pass the user's email address, phone number (optional), and their password hash (optional) into the corresponding Stytch API endpoints:
- If the user is passwordless, use the Create Member endpoint.
- If the user has a password, use our Migrate Password endpoint.
- If the user has a password and two factors (e.g. email and phone), first use the Create Member endpoint to add the email_address + mfa_phone_number, then use the Migrate Password endpoint to add the password hash.
Stytch offers the option to either allow end users to use the same password across all Organizations they belong to under that email or to scope passwords to the specific Member/Organization. This setting cannot be changed once you have active passwords in your project, so prior to kicking off your migration update your password settings in the Stytch Dashboard to match the password behavior that you would like.
If you want to allow passwords to be used across Organizations, you only need to call the Migrate Password endpoint one time for a given email -- even if the email is associated with multiple Members. If you want passwords to be scoped to the Member/Organization, you will call the Migrate Password endpoint for each MemberID you've migrated to Stytch.
You may call Migrate Password endpoint for existing Stytch Members, using the email_address associated with the Member. Stytch will recognize the email address and add the password hash to the exising Member object or allow for use across mulitple Member objects depending on your setting.
curl --request POST \
--url https://test.stytch.com/v1/b2b/organizations/{ORGANIZATION_ID}/members \
-u 'PROJECT_ID}:SECRET' \
-H 'Content-Type: application/json' \
-d '{
"name": "Ada Lovelace",
"email_address": "adalovelace@stytch.com"
}'
What's next
Check out the additional migration considerations guide to learn how to move your app logic to Stytch and for more user import guidance.