diff --git a/src/content/docs/get-started/switch-to-kinde/auth0-to-kinde.mdx b/src/content/docs/get-started/switch-to-kinde/auth0-to-kinde.mdx index 330a0b65d..d38bd9cfd 100644 --- a/src/content/docs/get-started/switch-to-kinde/auth0-to-kinde.mdx +++ b/src/content/docs/get-started/switch-to-kinde/auth0-to-kinde.mdx @@ -3,13 +3,20 @@ page_id: b338980f-7dd6-4ba5-90aa-330247a45536 title: Migrate to Kinde from Auth0 sidebar: order: 2 + label: Auth0 +tableOfContents: + maxHeadingLevel: 3 relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 - e89d246a-5cdf-4993-9cee-94b31ec27583 - - d9980c1a-71c8-4fe9-8433-4ff09c9fe6ee -description: Comprehensive guide to migrating from Auth0 to Kinde including user data export, password migration, social identities, and organizational setup. +description: Export users and passwords from Auth0 and migrate to Kinde, with guidance on handling social identities, the migration window, and drip-feed options. topics: - get-started - switch-to-kinde + - user-management + - authentication sdk: [] languages: - json @@ -21,160 +28,166 @@ audience: complexity: advanced keywords: - auth0 migration + - migrate from auth0 + - auth0 to kinde - user import - password migration + - password export + - bulk import + - drip-feed migration + - ndjson + - user export extension + - resource owner password credentials + - ropc + - social identities + - identity provider + - migration window - oauth2 - oidc - - social identities - organizations - roles - permissions -updated: 2024-01-15 +updated: 2026-05-05 featured: false deprecated: false -ai_summary: Comprehensive guide to migrating from Auth0 to Kinde including user data export, password migration, social identities, and organizational setup. +ai_summary: "Step-by-step guide for migrating users from Auth0 to Kinde. Covers installing the Auth0 User Import/Export extension, exporting user data as NDJSON (including the identities field for social logins), and preparing your Kinde business with matching auth methods, organizations, roles, and permissions. Explains three migration methods: drip-feed via the Kinde `user:existing_password_provided` workflow (recommended — no bulk export, no downtime), an app-hosted manual flow using Auth0's Resource Owner Password Credentials endpoint, and bulk import with a hard cutover. Includes guidance on handling new registrations and password changes during the migration window, supported authentication connection types, and a mapping of Auth0 concepts (tenants, environments, identity providers, Universal Login) to their Kinde equivalents. Also covers options when Auth0 password export is unavailable or impractical, such as importing users without passwords and letting Kinde prompt a reset on first sign-in." --- -This guide is designed to help you migrate from Auth0 to Kinde. - -Switching between providers for any service can be daunting, and especially where user data is involved. We’ll walk you through the process or migrating, to take some of the pain away. +This guide covers the Auth0-specific steps for exporting your users and migrating to Kinde. -If you’ve got a lot of users (your export file is over 20MB) or are concerned about file size limits, you can contact us to ensure the import goes smoothly. - -## Still not sure about moving to Kinde? +A key point to note: Kinde is OAuth2/OIDC compatible and issues similar tokens to Auth0. You only need to update the token claims when you migrate. If you want to compare Kinde with Auth0, [this page](https://kinde.com/comparisons/auth0-alternative/) has some useful information. -A key point to note is that Kinde is OAuth2/OIDC compatible, issuing similar tokens to Auth0. You only need to update the token claims when you migrate. - -## Step 1: Prepare your Kinde business for migration +### What you need -If you haven’t already got a Kinde account, [register for free here](https://app.kinde.com/register) (no credit card required). +- A Kinde account with **Admin** access +- Kinde account configured to match your current auth provider - see [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate) +- Auth0 account with extension installation permissions -- Set up the [authentication methods](/authenticate/about-auth/about-authentication/) in Kinde. You can replicate the auth methods you currently use with Auth0, or [set up new methods for users](/authenticate/authentication-methods/set-up-user-authentication/), e.g. passwordless. -- If your users sign in with passwords, be sure to enable [password authentication](/authenticate/authentication-methods/password-authentication/). -- [Create organizations in Kinde](/build/organizations/add-and-manage-organizations/) - only if you use this function to support multi-tenancy (for example, in a B2B structure) or if you manage separate user groups this way. -- Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde, if you intend to import these details with users. -- Review the [Migrating other objects](/get-started/switch-to-kinde/auth0-to-kinde/#other-objects-you-may-want-to-bring-from-auth0) topic below. +## Key considerations -## Step 2: Get the Auth0 extension to export users +- **Password export takes time** — Auth0 takes up to 2 weeks to fulfil a password export request on some plans. Plan your migration window accordingly, or use drip-feed migration to avoid waiting. +- **File size limit** — import files are limited to 20MB. Split large exports into batches. +- **Format** — Auth0 exports in NDJSON (Newline Delimited JSON), not CSV. Kinde's Auth0 import accepts this format directly. +- **Social identities** — social logins (Google, GitHub, etc.) are stored in the `identities` array. Kinde imports these and lists them under the user's profile. Users without an email can be imported and are identified by the `connection` attribute. +- **Users with multiple identities** — these are imported and listed under the user's profile in Kinde. +- **Handling new registrations during the migration window** — see [Choose your migration method](#choose-your-migration-method) below. -Auth0 doesn’t have an export option by default, so you’ll need to install an export extension. +## Export user data from Auth0 -1. Go to [Auth0 Dashboard > Extensions](https://manage.auth0.com/#/extensions), and select **User Import / Export**. -2. When prompted, select **Install**. +### 1. Install the Auth0 export extension -![Auth0 extension screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/2a8f1e39-2050-4c14-146a-338ecb57bb00/public) +Auth0 doesn't have an export option by default, so you'll need to install an extension. -You'll now see it in your list of installed extensions. The first time you launch it, you'll be asked to grant permission for the extension to access your Auth0 account. +1. Go to [Auth0 Dashboard > Extensions](https://manage.auth0.com/#/extensions) and select **User Import / Export**. +2. Select **Install**. -## Step 3: Export user data from Auth0 +![Auth0 extension screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/2a8f1e39-2050-4c14-146a-338ecb57bb00/public) -File format guidelines: +The extension appears in your list of installed extensions. The first time you launch it, you'll be asked to grant permission to access your Auth0 account. -- User details and passwords must be in NDJSON (Newline Delimited JSON) format -- Import file size limit is 20MB. You may need to split the file if the exported size exceeds this. +### 2. Export user data from Auth0 -### Supported auth methods +1. Launch the extension by selecting **Import / Export Extension**. +2. Select **Export**. -Kinde supports migrating the following authentication methods from Auth0: Usernames, Email, Phone, Google, Apple, Microsoft, Facebook, GitHub, Twitch, Bitbucket. If you need to migrate another authentication type from Auth0 please get in touch with support. + ![Auth0 export selections screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/0748f464-d46f-4455-20dc-8f1c677fbb00/public) -Auth methods are shown in the `connection` attribute. These are represented as follows in the identity array: +3. Select **Add default fields** and add the **identities** field. +4. Change the **Export Format** to **.json**. +5. Select **Export [X] Users**. Once complete, select **Download**. -- Username-Password-Authentication -- email -- sms -- google-oauth2 -- github -- twitch -- facebook -- bitbucket -- windowslive + You will have an NDJSON (.json) file to import into Kinde -### Can’t get the passwords from Auth0? +## Choose your migration method -Some Auth0 plans don’t allow password exports, or you might not want to wait 2 weeks for the file. If this is the case, import the user data you’re able to, and Kinde will ask users to set a new password the next time they sign in. +### Drip-feed via Kinde Workflow (recommended) -### Export Auth0 data +Use the `user:existing_password_provided` workflow trigger to validate credentials against Auth0 automatically on first login. No bulk export needed, no downtime. -1. Launch the extension by selecting **Import / Export Extension.** -2. Export your existing Auth0 users associated with database connections, select **Export**. +The workflow calls Auth0's Resource Owner Password Flow (`POST /oauth/token`) to verify the password before creating the user in Kinde. - ![Auth0 export selections screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/0748f464-d46f-4455-20dc-8f1c677fbb00/public) +[Set up drip-feed migration →](/workflows/workflow-tutorials/drip-feed-migration/) -3. Select **Add default fields** and add the **identities** field to the import list. **Identities** data distinguishes the type of identity, e.g. username, phone, GitHub, Google, etc. -4. Change the **Export Format** to **.json**. -5. When you're ready, click **Export [X] Users.** (**X** is the number of users you're exporting). -6. Once the export is complete, select **Download** to get the file containing your user’s information. This is the main file you’ll need to migrate your users; the other file is the password hashes. +### App-hosted manual flow -## Step 4: Import user data into Kinde +If your app hosts its own login form (email + password), you can push users to Kinde directly without a Kinde workflow: -1. In Kinde, go to **Users**, then select **Import users**. -2. Select **Auth0.** +1. When a user signs in to your legacy app, check if they exist in Kinde: `GET /api/v1/users?email={email}`. +2. If not, validate their password against Auth0's ROPC endpoint: - ![Import from Kinde tool screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/10090edb-3f26-405d-898d-2dfedd155100/public) + ```http + POST https://YOUR_DOMAIN/oauth/token + { + "grant_type": "password", + "username": "{user_email}", + "password": "{user_password}", + "audience": "{your_api_identifier}", + "client_id": "{client_id}", + "client_secret": "{client_secret}" + } + ``` -3. You’ll be presented with 2 options: - 1. **Import users only** - import users first and passwords after. You can also use this method if you want to allow users to reset their password or sign in another way. - 2. **Import passwords only** - only choose this if you have already imported users. -4. Follow the on-screen prompts to import the data. -5. If there are any [errors with the import](/manage-users/add-and-edit/troubleshoot-user-import-errors/), you will be able to view them afterwards. -6. Most import errors can be fixed by editing the json file and then - re-importing into Kinde. +3. A `200 OK` response confirms valid credentials. Create the user in Kinde and set their password. +4. On next login, route the user to Kinde's hosted login. -Once the password hashes have been imported, your users will be able to sign in to Kinde with their existing password. +For the Kinde API steps, see [Create users with the API](/get-started/switch-to-kinde/create-users-with-api/). -### How Auth0 user identities are treated on import +### Bulk import (hard switch) -Social identities without an email can be imported and are identified by the `connection` attribute. -You can also import users with multiple identities; these will be listed under the user’s profile. +Export users and passwords from Auth0, import into Kinde, then switch. Follow the steps below: -## After the migration +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Auth0**. -### **Communication to users after import** + ![Import from Kinde tool screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/06ceef1a-0236-4f42-6598-c60dd511a400/socialsharingimage) -Kinde does not send any notifications or invitations to users when they are added to Kinde via import. The idea is that your users have a seamless experience that feels (almost) like it always has in your app. +3. Choose **Import users only** (import users first, then passwords separately) or **Import passwords only** (if users are already imported). +4. Follow the on-screen prompts to upload the file. +5. Review any [import errors](/manage-users/add-and-edit/troubleshoot-user-import-errors/) afterwards. Most can be fixed by editing the file and re-importing. -Similarly, if you add users via API, Kinde does not send an email or notification to the user. +For full import details, see [Bulk import users](/get-started/switch-to-kinde/migrate-users-bulk-import/). -If you’ve made changes to their sign in experience — for example adding multi-factor authentication — then consider contacting your users to let them know their sign in experience will be changed. +To handle new registrations or password changes during the migration window: -### Additional consequences of migration +- Re-export and re-import from Auth0 to catch new registrations. Users who registered after your first export won't be able to sign in until the second import completes. +- Use the [API to force a password reset](/get-started/switch-to-kinde/create-users-with-api/) for users whose password changed during the window. -Importing all your existing users and passwords following the above process should mean that your users won’t notice anything when they next sign in. This is the optimal experience. However: +## More topics -- If a user changes their password after the user export and while the migration is in progress, they will need to reset their password to sign in. -- If you have set up a new authentication method as part of the user migration (for instance, going password-less) your users will be prompted to use the new method on sign in. -- If you add or remove roles or permissions, users may gain/lose access to parts of your system. +### Supported auth methods -During and following the migration, we recommend checking for these issues. +Kinde supports migrating these authentication methods from Auth0: usernames, email, phone, Google, Apple, Microsoft, Facebook, GitHub, Twitch, Bitbucket. Contact support if you need to migrate another type. -### There is no check for weak passwords +Auth methods are shown in the `connection` attribute of the `identities` array: -When you import passwords, Kinde does not check for password strength. You’ll want to enforce your own password policies for users. +- `Username-Password-Authentication` +- `email` +- `sms` +- `google-oauth2` +- `github` +- `twitch` +- `facebook` +- `bitbucket` +- `windowslive` ### Other objects you may want to bring from Auth0 -If you have important objects that need to be migrated, such as organizations or roles outside the basic user information, you can import them, or add them via the [Kinde management API](/kinde-apis/management/). - -Before you migrate, however, be aware that the functionality of these objects may differ between Auth0 and Kinde. Here’s some similarities and differences to note: - -- Auth0 has the concept of [Tenants](https://auth0.com/docs/get-started/learn-the-basics) which group other objects such as users and applications together. Kinde calls these [Businesses](/build/set-up-options/run-multiple-businesses/) and is set up to allow you to run multiple businesses with a single Kinde account. -- Both Kinde and Auth0 have [Organizations](/build/organizations/multi-tenancy-using-organizations/) to allow you to build multi-tenant applications. The main difference being that Kinde treats organizations as a first class citizen. -- Each business Kinde allows you to have multiple [Environments](/build/environments/environments/) and these contain organizations, users and applications. -- In Auth0, [Applications](https://auth0.com/docs/applications/set-up-an-application) are what your users can sign in to. They are also called [Applications](/build/applications/add-and-manage-applications/) in Kinde and work in essentially the same way. -- In Auth0, [Identity Providers](https://auth0.com/docs/identityproviders) are a source of data for users. Kinde calls these connections or authentication providers. -- In Auth0, [Roles and Permissions](https://auth0.com/docs/authorization/rbac/roles) provide information about what your users can do in your applications. Kinde also has [Roles](/manage-users/roles-and-permissions/user-roles/) and [Permissions](/manage-users/roles-and-permissions/user-permissions/) and they are assigned on a per user, per organization basis, meaning the same user can have different permissions in different organizations. For the Auth0 equivalent of user-level roles/permissions, use the [default organization](/build/organizations/orgs-for-developers/). -- Kinde’s hosted sign-up pages are a very similar concept to [Auth0’s Universal Login](https://auth0.com/docs/authenticate/login/auth0-universal-login). +- **Tenants** → [Businesses](/build/set-up-options/run-multiple-businesses/) in Kinde. A single Kinde account can run multiple businesses. +- **Organizations** → [Organizations](/build/organizations/multi-tenancy-using-organizations/) in Kinde. Kinde treats organizations as first-class citizens. +- **Environments** → Kinde [Environments](/build/environments/environments/) contain organizations, users, and applications. +- **Applications** → [Applications](/build/applications/add-and-manage-applications/) in Kinde work in essentially the same way. +- **Identity Providers** → connections or authentication providers in Kinde. +- **Roles and Permissions** → Kinde [Roles](/manage-users/roles-and-permissions/user-roles/) and [Permissions](/manage-users/roles-and-permissions/user-permissions/) are assigned per user per organization. For Auth0's equivalent of user-level roles/permissions, use the [default organization](/build/organizations/orgs-for-developers/). +- Auth0's Universal Login → Kinde's hosted sign-up pages work the same way. -## Help is here +Import objects via the [Kinde Management API](/kinde-apis/management/), or add them in the Kinde dashboard. -We’ve tried to make onboarding to Kinde as easy as possible, because we know it’s a pain to break up with your old provider. We’re here to help and can assist with your migration. +### Can't get passwords from Auth0? -Contact us via: [Slack](https://thekindecommunity.slack.com/join/shared_invite/zt-26hdaavyc-CfOa06vP23guSwK~~OpFMQ#/shared-invite/email), [Discord](https://discord.com/invite/wHX6j7wG5d), [Email](mailto:support@kinde.com), [Chat](https://chat.kinde.com) +Some Auth0 plans don't allow password exports, or the 2-week wait isn't practical. If that's the case, import users without passwords — Kinde will ask them to set a new password on first sign-in. Alternatively, use [drip-feed migration](/workflows/workflow-tutorials/drip-feed-migration/) to avoid the export entirely. -Book a call for: +## Get support -- [General or account questions](https://meetings.hubspot.com/kinde/kinde-demo) -- [Technical questions](https://meetings.hubspot.com/kinde/kinde-demo) (we will make sure we have engineers on the call to help) -- [Security and compliance questions](https://meetings.hubspot.com/kinde/kinde-demo) +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) \ No newline at end of file diff --git a/src/content/docs/get-started/switch-to-kinde/aws-cognito-to-kinde.mdx b/src/content/docs/get-started/switch-to-kinde/aws-cognito-to-kinde.mdx new file mode 100644 index 000000000..4bdaf1f66 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/aws-cognito-to-kinde.mdx @@ -0,0 +1,114 @@ +--- +page_id: df969c6a-b071-46fe-958a-df2a8f913428 +title: Migrate to Kinde from AWS Cognito +sidebar: + order: 6 + label: AWS Cognito +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Export users from AWS Cognito and migrate to Kinde. Because Cognito does not export passwords, drip-feed migration is the recommended approach for a seamless user experience. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - bash + - csv +audience: + - developers + - admins +complexity: advanced +keywords: + - aws cognito migration + - cognito to kinde + - migrate from cognito + - cognito export + - user pool export + - drip feed migration + - admin user password auth +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "Step-by-step guide for migrating users from AWS Cognito to Kinde. Because Cognito does not export hashed passwords, drip-feed migration is the recommended approach — using Kinde's user:existing_password_provided workflow trigger to validate each user's password against Cognito on first login via the ADMIN_USER_PASSWORD_AUTH flow, with no password reset required. Covers exporting users from Cognito using the AWS CLI with list-users, paginating large user pools, and converting the JSON output to a Kinde-compatible CSV using the Cognito sub as the id field. Also covers the bulk import fallback for cases where drip-feed is not an option, where users are imported by email only and prompted to set a new password on first sign-in. Includes prerequisites: enabling ADMIN_USER_PASSWORD_AUTH on the Cognito App Client and enabling Enumeration protection in Kinde before starting drip-feed migration." +--- + +Migrate your users from AWS Cognito to Kinde. The main constraint is that Cognito does not allow password export, so a direct password migration is not possible — drip-feed migration is the recommended path. + +### What you need + +- A Kinde account with **Admin** access +- Kinde account configured to match your current auth provider — see [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate) +- AWS CLI installed and configured with access to your Cognito User Pool + +## Key considerations + +- **No native export UI** — Cognito doesn't have a one-click export. You'll need to use the AWS CLI or write a script to paginate through the user pool. +- **Passwords cannot be exported** — Cognito does not provide access to hashed passwords. Users imported from Cognito will need to reset their password or sign in via a new method — unless you use drip-feed migration. +- **Drip-feed migration is the recommended approach** — using Kinde's `user:existing_password_provided` workflow, you can validate each user's password against Cognito on first login and migrate them seamlessly with no password reset required. + +## Export users from Cognito + +### 1. Export user data + +Cognito has no UI export. Use the AWS CLI to list users from your User Pool: + +```bash +aws cognito-idp list-users \ + --user-pool-id YOUR_USER_POOL_ID \ + --region YOUR_AWS_REGION \ + --query 'Users[*].{email:Attributes[?Name==`email`].Value|[0], sub:Username, name:Attributes[?Name==`name`].Value|[0]}' \ + --output json > cognito-users.json +``` + +For large user pools, use `--pagination-token` to page through results, or use a script to loop until all users are retrieved. + +### 2. Prepare your CSV + +Convert the JSON output to a Kinde-compatible CSV. The `id` field should be the Cognito `sub` (the user's UUID in Cognito). + +```text +id,email,first_name,last_name,email_verified +{sub},{email},{given_name},{family_name},TRUE +``` + +For the full list of supported CSV fields — including organizations, roles, and permissions — see [Prepare your CSV](/get-started/switch-to-kinde/migrate-users-bulk-import/#3-prepare-your-csv) in the bulk import guide. + +## Choose your migration method + +### Drip-feed via Kinde Workflow (recommended) + +Migrate users with no downtime and no password resets. On first login, a Kinde workflow validates the user's password against Cognito using the `ADMIN_USER_PASSWORD_AUTH` flow. If valid, the user is created in Kinde and their password is set. + +**Before you start:** + +1. [Bulk import](/get-started/switch-to-kinde/migrate-users-bulk-import/) user email addresses (without passwords) to seed Kinde with your user list. +2. Ensure `ADMIN_USER_PASSWORD_AUTH` is enabled on your Cognito App Client. +3. Enable **Enumeration protection** in Kinde: **Settings > Attack protection > Enumeration protection**. + +The [drip-feed migration tutorial](/workflows/workflow-tutorials/drip-feed-migration/) includes the Cognito-specific workflow code. + +### Bulk import (with password reset) + +If drip-feed is not an option, import users by email only. Users will be prompted to set a new password or sign in via a passwordless method on first sign-in. + +1. Export emails and user details using the CLI command above. +2. Prepare your CSV (no password columns) - see the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) +3. Enable passwordless sign-in or password authentication in Kinde. +4. Go to Kinde > **Users**, select **Import users**, then select **Custom CSV**. +5. Follow the on-screen prompts to upload your file. +6. Review any errors reported after import. Fix the CSV and re-import to resolve them. + +## Next steps + +- If using drip-feed, monitor the workflow logs to confirm users are migrating successfully. +- Once migration traffic from Cognito drops to zero, disable the workflow and decommission your Cognito User Pool. +- For users who never log in during the migration period, decide whether to keep them (force a password reset via [the API](/get-started/switch-to-kinde/create-users-with-api/)) or remove inactive accounts. + +## Get support + +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) diff --git a/src/content/docs/get-started/switch-to-kinde/azure-b2c-to-kinde.mdx b/src/content/docs/get-started/switch-to-kinde/azure-b2c-to-kinde.mdx new file mode 100644 index 000000000..98e7dfb0a --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/azure-b2c-to-kinde.mdx @@ -0,0 +1,138 @@ +--- +page_id: d0e70a47-6e28-4a63-8215-76eec9fee0a0 +title: Migrate to Kinde from Azure B2C +sidebar: + order: 7 + label: Azure B2C +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Export users from Azure B2C and migrate to Kinde. Azure B2C does not export passwords, so choose between bulk import with password reset, API-based migration, drip-feed, or a hard cutover. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - bash + - csv +audience: + - developers + - admins +complexity: advanced +keywords: + - azure b2c migration + - azure ad b2c + - migrate from azure + - azure b2c export + - user migration + - drip feed migration + - ropc + - resource owner password credentials +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "Step-by-step guide for migrating users from Azure B2C to Kinde. Because Azure B2C does not export passwords, the guide covers four migration approaches: drip-feed (recommended), bulk import with API sync, bulk import only, and hard cutover. Drip-feed uses Kinde's user:existing_password_provided workflow trigger to validate each login against Azure B2C's ROPC endpoint on first sign-in, with no password reset required. Bulk import options import users by email only and prompt them to set a new password or use passwordless on first sign-in. Covers exporting users via the Azure portal Download users option or programmatically via the Microsoft Graph API with pagination, and maps Azure B2C fields (id, mail, givenName, surname, accountEnabled) to Kinde's CSV format. Includes guidance on handling local accounts vs. federated social identities, setting up the MS Entra ID connection in Kinde before importing AD-based users, and enabling the ROPC user flow in Azure B2C and Enumeration protection in Kinde before starting drip-feed migration." +--- + +Migrate your users from Azure B2C to Kinde. Azure B2C does not export passwords, so the migration approach you choose will determine how users authenticate on first sign-in. + +### What you need + +- A Kinde account with **Admin** access +- Kinde account configured to match your current auth provider — see [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate) +- Azure B2C tenant with user export permissions + +## Key considerations + +- **Passwords cannot be exported** — Azure B2C does not provide access to hashed passwords. Users will need to reset their password or use a new sign-in method, unless you use drip-feed migration. +- **Local accounts vs. federated identities** — users who signed in via social providers (Google, Facebook, etc.) in Azure B2C can be imported by email and prompted to re-link their social login. +- **MS Entra ID connection** — if you use Azure AD-based logins, [set up the MS Entra ID connection in Kinde](/authenticate/enterprise-connections/azure/) before importing users so Kinde can match them to the right connection. + +## Export users from Azure B2C + +### Option A: Azure portal + +1. In the [Azure portal](https://portal.azure.com/), go to **Azure AD B2C**. +2. Select **Users** from the left menu. +3. Select **Download users** to export a CSV of all users. + +The portal export includes basic user properties (email, display name, object ID). It does not include passwords. + +### Option B: Microsoft Graph API (recommended for large user bases) + +Use the Microsoft Graph API to export users programmatically with full control over which attributes are included: + +```bash +GET https://graph.microsoft.com/v1.0/users?$select=id,displayName,givenName,surname,mail,userPrincipalName,accountEnabled +Authorization: Bearer {access_token} +``` + +Paginate using the `@odata.nextLink` value in the response. Convert the output to a Kinde-compatible CSV. + +**Column mapping:** + +| Azure B2C field | Kinde column | +|-----------------|--------------| +| `id` | `id` | +| `mail` or `userPrincipalName` | `email` | +| `givenName` | `first_name` | +| `surname` | `last_name` | +| `accountEnabled` | `email_verified` (use `TRUE`/`FALSE`) | + +## Choose your migration method + +### Drip-feed (recommended) + +Migrate users seamlessly as they log in. A Kinde workflow validates each login against Azure B2C's ROPC endpoint, creates the user in Kinde on success, and takes over authentication going forward. + +**Before you start:** +1. [Bulk import](/get-started/switch-to-kinde/migrate-users-bulk-import/) user email addresses (without passwords) to seed Kinde. +2. Enable **Enumeration protection** in Kinde (**Settings > Attack protection > Enumeration protection**). +3. Enable the ROPC user flow in your Azure B2C tenant. + +The [drip-feed migration tutorial](/workflows/workflow-tutorials/drip-feed-migration/) includes the Azure B2C-specific workflow code. + +### Bulk import with API sync (catch new registrations) + +Export users and import into Kinde. During the migration window, use the Kinde API to push any new sign-ups from Azure B2C directly to Kinde so no one is missed. + +1. Set up an API integration to push new Azure B2C registrations to Kinde in real time. +2. Export existing users using the portal or Graph API. +3. Import into Kinde via [bulk import](/get-started/switch-to-kinde/migrate-users-bulk-import/). +4. Switch to Kinde. +5. Users will be prompted to set a new password or sign in via passwordless on first sign-in. + +See [Create users with the API](/get-started/switch-to-kinde/create-users-with-api/) for the Kinde API steps. + +### Bulk import only + +Simplest option. Export users, import into Kinde, switch. No API integration needed. + +1. Export users using the portal or Graph API. +2. Re-import before cutover to catch any new registrations. +3. Follow the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/). +4. Users set a new password or sign in via passwordless on first sign-in. + +### Hard cutover (maintenance window) + +For the cleanest cutover when a short service interruption is acceptable: + +1. Block new registrations in Azure B2C (not logins — since passwords aren't migrated, existing logins don't affect the migration). +2. Export all users. +3. Import into Kinde via [bulk import](/get-started/switch-to-kinde/migrate-users-bulk-import/). +4. Switch to Kinde. +5. Users set a new password or sign in via passwordless on first sign-in. + +## Next steps + +- If using drip-feed, monitor the workflow logs to confirm users are migrating successfully. +- Once migration traffic from Azure B2C drops to zero, disable the workflow and decommission your Azure B2C tenant. +- Notify users of the change before go-live — especially that they will need to verify their email or set a new password on first sign-in. + +## Get support + +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) \ No newline at end of file diff --git a/src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx b/src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx new file mode 100644 index 000000000..4aa10a053 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx @@ -0,0 +1,117 @@ +--- +page_id: 8b3e1d47-2f96-4a0c-c8d5-6e7a2b9f3150 +title: Migrate to Kinde from Clerk +sidebar: + order: 3 + label: Clerk +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - b338980f-7dd6-4ba5-90aa-330247a45536 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Export users and hashed passwords from Clerk and import them into Kinde. Clerk supports bcrypt exports, so users keep their existing passwords. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - csv +audience: + - developers + - admins +complexity: intermediate +keywords: + - clerk migration + - clerk to kinde + - migrate from clerk + - user import + - password migration + - hashed passwords + - bcrypt + - csv import + - csv column mapping + - bulk import + - authentication migration + - clerk export + - clerk csv +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "Step-by-step guide for migrating users from Clerk to Kinde using a bulk CSV import. Clerk supports exporting bcrypt-hashed passwords, and Kinde supports bcrypt natively, so users can sign in with their existing passwords without a forced reset — no drip-feed migration required. The guide covers: exporting users from the Clerk dashboard via Configure > Settings > User exports; renaming CSV columns to match Kinde's expected format, including primary_email_address to email, password_digest to hashed_password, password_hasher to hashing_method, and primary_phone_number to phone; removing columns Kinde does not use such as username, verified_email_addresses, totp_secret, and created_at; enabling password authentication in Kinde before importing; and uploading the prepared CSV via Users > Import users > Custom CSV. Errors flagged during import can be fixed by editing the CSV and re-importing — already-imported records are skipped. Links to the full bulk import guide for additional CSV fields covering organizations, roles, and permissions." +--- + +Migrate your users from Clerk to Kinde. Clerk supports exporting hashed passwords, and Kinde supports bcrypt — so your users can sign in with their existing passwords without a forced reset. + +### What you need + +- A Kinde account with **Admin** access +- Kinde account configured to match your current auth provider - see [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate) +- Clerk account with user export permissions + +## Key considerations + +- **bcrypt passwords are fully supported** — Kinde imports bcrypt hashes directly. Users keep their existing password with no reset required. +- **No drip-feed needed** — because passwords can be migrated cleanly, a straightforward bulk import is the recommended approach for most Clerk migrations. +- **File format** — Clerk exports a CSV file. You'll need to map the Clerk column names to Kinde's expected column names before importing. + +## Migration guide + +### 1. Export users from Clerk + +1. Sign in to your [Clerk dashboard](https://dashboard.clerk.com/apps). +2. Select the application you are exporting users from. +3. Go to **Configure > Settings**. +4. Under **User exports**, select **Export users**. +5. When the export is ready, select **Download**. This downloads a CSV file. + +![Clerk export users](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/466e727b-0a72-4475-a019-4a685579a200/socialsharingimage) + +See Clerk's documentation on [exporting users](https://clerk.com/docs/guides/development/migrating/overview#export-your-users-data-from-the-clerk-dashboard). + +### 2. Map Clerk columns to Kinde's CSV format + +Rename the columns in your Clerk export to match what Kinde expects. The only required column is `email` — everything else is optional but recommended. + +| Clerk column | Rename to | Notes | +|---|---|---| +| `primary_email_address` | `email` | Required — primary sign-in identifier | +| | `email_verified` | `TRUE` or `FALSE` | +| `id` | `id` | Keep as-is — helps match records on re-import | +| `first_name` | `first_name` | Keep as-is | +| `last_name` | `last_name` | Keep as-is | +| `primary_phone_number` | `phone` | International format, e.g. `+61555111555` | +| `password_digest` | `hashed_password` | bcrypt hash — preserves existing passwords | +| `password_hasher` | `hashing_method` | Value will be `bcrypt` | + +For the full list of supported CSV fields — including organizations, roles, and permissions — see [Prepare your CSV](/get-started/switch-to-kinde/migrate-users-bulk-import/#3-prepare-your-csv) in the bulk import guide. + + + +### 3. Import into Kinde + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Custom CSV**. +3. Follow the on-screen prompts to upload your file. +4. Review any errors reported after import. Fix the CSV and re-import to resolve them. + +See the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to learn more. + +### 4. Test the migration + +1. Sign in to Kinde with a user from your Clerk export. +2. Verify they can sign in with their existing Clerk credentials. +3. Notify users of any changes to their sign-in experience before going live. + +## Troubleshooting + +Review the CSV for missing or duplicated values before importing. Kinde flags errors during import and reports them. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes are skipped. + +## Get support + +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) \ No newline at end of file diff --git a/src/content/docs/get-started/switch-to-kinde/create-users-with-api.mdx b/src/content/docs/get-started/switch-to-kinde/create-users-with-api.mdx new file mode 100644 index 000000000..a9f7ec797 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/create-users-with-api.mdx @@ -0,0 +1,169 @@ +--- +page_id: 98a6a913-a9ba-474c-8b01-6db706d08b4c +title: Create users with the Kinde API during migration +description: Use the Kinde Management API to create users programmatically during a migration — catching new sign-ups and password changes in real time. +sidebar: + order: 9 + label: Create users with API +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +topics: + - get-started + - switch-to-kinde + - developer-tools +sdk: [] +languages: + - json + - bash +audience: + - developers +complexity: advanced +keywords: + - api migration + - create users api + - user migration + - migration window + - programmatic migration + - management api + - user provisioning + - password hash migration + - bcrypt migration + - machine to machine + - M2M application + - real-time user sync + - set password api + - identity migration +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "This guide explains how to use the Kinde Management API to create and provision users programmatically during a migration. It covers three primary use cases — acting as a real-time safety net during a migration window to capture new sign-ups and password changes, integrating with custom auth systems where the developer controls the login form, and syncing passwords when users authenticate against a legacy system. The guide walks through four core API steps: checking whether a user already exists to avoid duplicates (GET /api/v1/users?email=), creating a new user with profile and identity data (POST /api/v1/user), setting a password using either a hashed value with a supported hashing method (bcrypt, md5, sha256, crypt, wordpress) or plaintext (PUT /api/v1/users/{user_id}/password), and optionally forcing a password reset when credentials may be out of sync. It also covers the end-to-end migration window pattern — bulk importing existing users first, intercepting live traffic during the transition via API, and running a final sync post-cutover — along with rate limit guidance and when to prefer CSV bulk import over the API approach." +--- + +Use the Kinde Management API to create and provision users programmatically — the right approach when you need to intercept live sign-ups or password changes during a migration window, or when you control the login form in a custom auth system and can hook directly into the sign-in path. + +## When to use this approach + +- **Migration window safety net** — your app intercepts logins/sign-ups in your legacy system and pushes users to Kinde in parallel, so no one is missed during the transition. +- **Custom auth systems** — you host your own login form and can add a Kinde API call to the sign-up/sign-in path. +- **Real-time password sync** — when a user successfully authenticates against your old system, you create them in Kinde with the same password. + +For automated drip-feed migration (no code changes to your app), see [Drip-feed migration](/get-started/switch-to-kinde/drip-feed-migration/) instead. + +### What you need + +- A Machine to Machine application authorized to use the Kinde Management API - see the [quickstart guide](/developer-tools/kinde-api/connect-to-kinde-api/). +- Required scopes: `create:users` and `update:user_passwords` +- A preferred way to use the Management API (Node.js, Python, etc.) - [see usage guide](/developer-tools/kinde-api/access-token-for-api/). + +## Core API steps + +### 1. Check if the user already exists + +Before creating a user, check whether they already exist in Kinde to avoid duplicates. + +```bash +GET https://your-kinde-domain.kinde.com/api/v1/users?email={user_email} +Authorization: Bearer {access_token} +``` + +- If the response returns a user, skip creation and go to Step 3 to update their password if needed. +- If the response is empty, proceed to Step 2. + +### 2. Create the user + +```bash +POST https://your-kinde-domain.kinde.com/api/v1/user +Authorization: Bearer {access_token} +Content-Type: application/json +``` + +```json +{ + "profile": { + "given_name": "Lee", + "family_name": "Liu", + "email": "lliu@company.com" + }, + "identities": [ + { + "type": "email", + "details": { + "email": "lliu@company.com" + } + } + ] +} +``` + +A successful response returns the new user's Kinde ID (`id`). Save this for the next step. + +### 3. Set the user's password + +```bash +PUT https://your-kinde-domain.kinde.com/api/v1/users/{user_id}/password +Authorization: Bearer {access_token} +Content-Type: application/json +``` + +```json +{ + "hashed_password": "$2a$10$examplehashvalue", + "hashing_method": "bcrypt", + "is_temporary_password": false +} +``` + +Supported `hashing_method` values: `bcrypt`, `md5`, `sha256`, `crypt`, `wordpress`. + +If you have access to the user's plaintext password at the time of login (because your app owns the login form), you can set it directly: + +```json +{ + "password": "userPlaintextPassword", + "is_temporary_password": false +} +``` + +### 4. Force a password reset (optional) + +If a user changed their password during the migration window and their hash in Kinde is out of date, prompt them to reset it: + +```bash +PATCH https://your-kinde-domain.kinde.com/api/v1/users/{user_id} +Authorization: Bearer {access_token} +Content-Type: application/json +``` + +```json +{ + "is_password_reset_requested": true +} +``` + +The user will be prompted to set a new password on their next sign-in. + +## Handling the migration window + +The typical pattern when running a migration window alongside live traffic: + +1. **Before cutover** — bulk import existing users from a CSV (see [Bulk import](/get-started/switch-to-kinde/migrate-users-bulk-import/)). +2. **During the window** — intercept sign-ups and sign-ins in your legacy system. For each: + - Check if the user exists in Kinde (`GET /api/v1/users?email=`). + - If not, create them (`POST /api/v1/user`) and set their password. + - If they exist but their password may have changed, update the password (`PUT /api/v1/users/{id}/password`). +3. **After cutover** — route all auth traffic to Kinde. Run a final re-import or re-sync to catch any users you missed. + +## Rate limits and batching + +The Kinde Management API has [rate limits](/developer-tools/kinde-api/api-rate-limits/). For large user bases: + +- Batch API calls and add delays between requests. +- For bulk provisioning of thousands of users, prefer the [CSV import](/get-started/switch-to-kinde/migrate-users-bulk-import/) method — it's designed for volume. +- Use the API approach for incremental syncing (new users, password changes) rather than full migrations. + +For full API reference, see the [Kinde Management API docs](/kinde-apis/management/). diff --git a/src/content/docs/get-started/switch-to-kinde/drip-feed-migration.mdx b/src/content/docs/get-started/switch-to-kinde/drip-feed-migration.mdx new file mode 100644 index 000000000..1007c3e50 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/drip-feed-migration.mdx @@ -0,0 +1,57 @@ +--- +page_id: f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 +title: Drip-feed migration to Kinde +sidebar: + order: 10 + label: Drip-feed migration +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - 0241b940-00bc-4ef0-b607-e70e388f4297 + - ca483387-5987-4449-a775-a9dfdedc0c7c +description: Progressively migrate users to Kinde as they log in, with no downtime, using the user:existing_password_provided workflow trigger. +topics: + - get-started + - switch-to-kinde + - workflows +sdk: [] +languages: + - typescript +audience: + - developers +complexity: advanced +keywords: + - drip feed migration + - progressive migration + - lazy migration + - on-demand migration + - password migration + - zero downtime migration + - no forced password reset + - user:existing_password_provided + - workflow trigger + - legacy auth migration + - kinde workflows + - gradual migration + - password validation +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "Drip-feed migration is a lazy, on-demand approach to moving users from a legacy auth system to Kinde — users are migrated automatically the first time they sign in, with no downtime and no forced password resets. It relies on the user:existing_password_provided Kinde workflow trigger, which fires when a user attempts to sign in with a password Kinde does not yet recognize. The workflow checks whether the user exists in Kinde; if not, it validates the submitted password against the legacy system via a secure API call. On a successful match, it creates the user in Kinde and sets their password so all future logins are handled by Kinde directly. Users who never sign in during the migration window can be handled separately via bulk import or the Management API. This approach requires no changes to the application's login flow — only a Kinde workflow and a validation endpoint on the legacy system. It suits large user bases where a one-time bulk migration is risky or impractical. Once all active users have migrated naturally, the legacy system can be safely decommissioned. This page is an overview; a full step-by-step implementation tutorial is linked at the bottom." +--- + +Drip-feed migration moves users from your legacy auth system to Kinde progressively as they log in — with no downtime, and no forced password resets. + +## How it works + +1. A user attempts to sign in to Kinde. +2. The `user:existing_password_provided` workflow trigger fires. +3. The workflow checks whether the user exists in Kinde. +4. If not, it validates the provided password against your legacy auth system via a secure API call. +5. If the password is valid, the workflow creates the user in Kinde and sets their password. +6. On all future logins, Kinde handles authentication directly. +7. Once all users have migrated naturally, decommission the legacy system. + +[Go to the full drip-feed migration tutorial →](/workflows/workflow-tutorials/drip-feed-migration/) diff --git a/src/content/docs/get-started/switch-to-kinde/firebase-to-kinde.mdx b/src/content/docs/get-started/switch-to-kinde/firebase-to-kinde.mdx new file mode 100644 index 000000000..ef0c95cfb --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/firebase-to-kinde.mdx @@ -0,0 +1,117 @@ +--- +page_id: f2a8d3e6-7c14-4b09-a5e1-3d8c7f29b045 +title: Migrate to Kinde from Firebase Authentication +sidebar: + order: 5 + label: Firebase +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - b338980f-7dd6-4ba5-90aa-330247a45536 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Export users from Firebase Authentication and import them into Kinde. Firebase uses SCRYPT password hashing which Kinde does not currently support, so plan for a passwordless or new-password flow. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - bash + - csv +audience: + - developers + - admins +complexity: intermediate +keywords: + - firebase migration + - firebase to kinde + - migrate from firebase + - firebase authentication + - firebase export + - firebase cli + - user import + - scrypt + - scrypt password + - password migration + - csv import + - csv column mapping + - bulk import + - authentication migration + - passwordless migration +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "Step-by-step guide for migrating users from Firebase Authentication to Kinde using a bulk CSV import. Firebase uses the SCRYPT hashing algorithm, which Kinde does not currently support, so password migration is not possible — users will need to sign in via a passwordless method or reset their password on first login. The drip-feed migration approach is also not applicable for Firebase. The guide covers: exporting users with the Firebase CLI using firebase auth:export users.json --format=json; mapping Firebase JSON fields to Kinde's CSV format, including localId to id, emailVerified to email_verified, and omitting passwordHash, salt, createdAt, disabled, and providerUserInfo; adding first_name, last_name, and phone manually if available from other sources; and uploading the prepared CSV via Users > Import users > Custom CSV in Kinde. It is recommended to enable at least one passwordless sign-in option in Kinde before cutover to ensure a smooth first sign-in for migrated users. Links to the bulk import guide for the full CSV field reference covering organizations, roles, and permissions." +--- + +Migrate your users from Firebase Authentication to Kinde. The process involves exporting user data from Firebase and importing into Kinde. + +### What you need + +- A Kinde account with **Admin** access +- Kinde account configured to match your current auth provider - see [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate) +- Firebase account with user export permissions + +## Key considerations + +- **SCRYPT passwords cannot be migrated** — Firebase uses the SCRYPT hashing algorithm, which Kinde does not currently support for import. Users will need to sign in via a new method (passwordless or social) or reset their password on first sign-in. +- **Drip-feed is not applicable** — because Firebase's SCRYPT hashes cannot be verified against a standard API, the drip-feed workflow approach is not available for Firebase migrations. +- **Recommended approach** — enable at least one passwordless option in Kinde before cutover, so users have a frictionless first sign-in. If password continuity is critical, [submit a feature request](https://updates.kinde.com/) to prioritize SCRYPT support. + +## Migration guide + +### 1. Export users from Firebase + +Make sure you have the [Firebase CLI](https://firebase.google.com/docs/cli) installed, then run: + +```bash +firebase auth:export users.json --format=json +``` + +This exports user records including email addresses, display names, UIDs, and hashed passwords. For full details, see the [Firebase Auth CLI documentation](https://firebase.google.com/docs/cli/auth). + +### 2. Map Firebase fields to Kinde's CSV format + +Rename the fields in your Firebase JSON export to match what Kinde expects, then save as a CSV. The only required column is `email` — everything else is optional but recommended. + +| Firebase field | Rename to | Notes | +|---|---|---| +| `email` | `email` | Required — primary sign-in identifier | +| `emailVerified` | `email_verified` | `TRUE` or `FALSE` | +| `localId` | `id` | Keep as Firebase UID — helps match records on re-import | +| first name (if available) | `first_name` | | +| last name (if available) | `last_name` | | +| phone number (if available) | `phone` | | +| `passwordHash` | — | Omit — Firebase uses SCRYPT, which Kinde does not support for import | +| `salt` | — | Omit | +| `createdAt` | — | Omit | +| `disabled` | — | Omit | +| `providerUserInfo` | — | Omit | + +For the full list of supported CSV fields — including organizations, roles, and permissions — see [Prepare your CSV](/get-started/switch-to-kinde/migrate-users-bulk-import/#3-prepare-your-csv) in the bulk import guide. + + + +### 3. Import into Kinde + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Custom CSV**. +3. Follow the on-screen prompts to upload your file. +4. Review any errors reported after import. Fix the CSV and re-import to resolve them. + +See the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to learn more. + +### 4. Test the migration + +1. Sign in to Kinde with a user from your Firebase export. +2. Verify the user can access your application. +3. Notify users of any changes to their sign-in experience before going live. + +## Get support + +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) diff --git a/src/content/docs/get-started/switch-to-kinde/migrate-users-bulk-import.mdx b/src/content/docs/get-started/switch-to-kinde/migrate-users-bulk-import.mdx new file mode 100644 index 000000000..0f5592140 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/migrate-users-bulk-import.mdx @@ -0,0 +1,178 @@ +--- +page_id: f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc +title: Bulk import users to Kinde +sidebar: + order: 8 + label: Bulk import +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - 98a6a913-a9ba-474c-8b01-6db706d08b4c + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Import users from a CSV or JSON file into Kinde, including hashed passwords, roles, and organizations. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - csv +audience: + - developers + - admins +complexity: intermediate +keywords: + - bulk import + - csv import + - user migration + - password migration + - hashed passwords + - import users + - migrate users + - bulk user migration + - password hash migration + - NDJSON import +updated: 2026-05-07 +featured: false +deprecated: false +ai_summary: "This guide explains how to bulk import users into Kinde using a CSV file (up to 5MB) or NDJSON for Auth0 exports (up to 20MB). It covers the full migration workflow: configuring your Kinde business with matching auth strategies, exporting users from providers like Auth0, Clerk, Supabase, Firebase, AWS Cognito, or Azure B2C, preparing a properly formatted file, and running the import via the Kinde dashboard. The guide details required and optional CSV columns including email, name, email verification status, organization IDs, roles, and permissions. It also covers migrating hashed passwords, with support for bcrypt, MD5, SHA256, crypt, and WordPress hashing methods, including salt configuration. Post-import guidance addresses handling new registrations and password changes during the migration window, recommending re-imports, forced password resets, or parallel API usage. The guide also notes that Kinde does not notify users on import, advising teams to plan their own communication strategy, and lists edge cases such as password changes mid-migration and how newly added authentication methods affect returning users." +--- + +Export your users from your existing auth system, prepare a CSV, and import them into Kinde. Users with migrated password hashes can sign in immediately with no password reset required. + +If you need to catch new registrations or password changes during the migration window, combine this with the [API approach](/get-started/switch-to-kinde/create-users-with-api/) or run a second import after the cutover. + +## Example CSV + +```text +# users.csv +email,first_name,last_name,email_verified,hashed_password,hashing_method,external_organization_id +bills@company.com,Bill,Smith,TRUE,$2a$10$examplehash,bcrypt,abc001 +carlosg@company.com,Carlos,Garcia,TRUE,$2a$10$examplehash,bcrypt,abc001 +lliu@company.com,Lee,Liu,FALSE,,, xyz002 +``` + +## Setup guide + +### 1. Prepare your Kinde business + +Configure your Kinde business with the same auth strategies as your existing provider. See [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate). + +### 2. Export users from your provider + +Export instructions vary by provider. Select yours: + +- [Auth0 →](/get-started/switch-to-kinde/auth0-to-kinde/) +- [Clerk →](/get-started/switch-to-kinde/clerk-to-kinde/) +- [Supabase →](/get-started/switch-to-kinde/supabase-to-kinde/) +- [Firebase →](/get-started/switch-to-kinde/firebase-to-kinde/) +- [AWS Cognito →](/get-started/switch-to-kinde/aws-cognito-to-kinde/) +- [Azure B2C →](/get-started/switch-to-kinde/azure-b2c-to-kinde/) + +If you are migrating from your own system, prepare the data to match the format described below. + +### 3. Prepare your CSV + +Kinde imports users from a CSV file (up to 5MB; Auth0 imports accept NDJSON up to 20MB). Format your export with the following columns. + +**Required column:** + +| Column | Notes | +|--------|-------| +| `email` | Minimum required field | + +**Recommended columns:** + +| Column | Notes | +|--------|-------| +| `first_name`, `last_name` | User's name | +| `email_verified` | `TRUE` or `FALSE` | +| `id` | Your provider's user ID — helps match records during re-imports | +| `phone` | International format, e.g. `+61555111555` | +| `external_organization_id` | Organization ID to import the user into. Comma-separate multiple values | +| `role_key` | Role key(s) to assign. Comma-separate multiple values | +| `permission_key` | Permission key(s) to assign. Comma-separate multiple values | + + + +**Password columns:** + +Include these if you're migrating hashed passwords: + +| Column | Notes | +|--------|-------| +| `hashed_password` | The hashed password string | +| `hashing_method` | See supported methods below | +| `salt` | Optional — extra characters added to strengthen the hash | +| `salt_position` | `prefix` or `suffix` — required if salt is included | +| `salt_format` | Format of the salt, e.g. `hex` or `string` | + +**Supported hashing methods:** + +| Method | Salt | Salt position | +|--------|------|---------------| +| `bcrypt` | — | — | +| `md5` | Optional | Required if salt included | +| `sha256` | Optional | Required if salt included | +| `crypt` | Optional | — | +| `wordpress` | Optional | — | + + + + + +**Check for errors before importing:** + +Review the CSV for missing or duplicate values. Kinde will report errors after import. Records that have already been imported without changes are skipped on re-import. + +### 4. Import users into Kinde + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select your import type: + - **Auth0** — for NDJSON files exported from Auth0 + - **Custom CSV** — for all other providers + + ![Import from Kinde tool screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/06ceef1a-0236-4f42-6598-c60dd511a400/socialsharingimage) + +3. Follow the on-screen prompts to upload your file. +4. Review any errors reported after import. Fix the CSV and re-import to resolve them. + +For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). + +## After the import + +### Handling new registrations during the migration window + +If users can still register or change their password while you migrate, you'll miss them. Options: + +- **Re-import** — run the export and import again after cutover to catch new registrations. Users who registered after your first export will be unable to sign in until this second import completes. +- **Force a password reset** — for users who changed their password during the window, use the [API to set `is_password_reset_requested`](/kinde-apis/management/#tag/Users/operation/updateUser). +- **Use the API in parallel** — push new sign-ups directly to Kinde via API during the migration window. See [Create users with the API](/get-started/switch-to-kinde/create-users-with-api/). + +### Communicating with users + +Kinde does not notify users when they are imported. Plan your own communication, especially if you're changing their sign-in experience (e.g. adding MFA or moving to passwordless). + +### Edge cases to watch + +- If a user changes their password after your export and before the migration completes, they will need to reset it. +- If you add a new authentication method (e.g. passwordless), users will be prompted to use it on next sign-in. +- Kinde does not check password strength on import — enforce your own policies for users. +- Adding or removing roles and permissions may change what users can access in your app. + +## Get support + +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) \ No newline at end of file diff --git a/src/content/docs/get-started/switch-to-kinde/supabase-to-kinde.mdx b/src/content/docs/get-started/switch-to-kinde/supabase-to-kinde.mdx new file mode 100644 index 000000000..af1ee5032 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/supabase-to-kinde.mdx @@ -0,0 +1,138 @@ +--- +page_id: 71acd8f5-eef5-4ebe-a1b0-2a1beeac32a0 +title: Migrate to Kinde from Supabase +sidebar: + order: 4 + label: Supabase +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - 8b3e1d47-2f96-4a0c-c8d5-6e7a2b9f3150 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Export users and hashed passwords from Supabase Auth and import them into Kinde. Supabase uses bcrypt, which Kinde supports natively — users keep their existing passwords. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - sql + - csv +audience: + - developers + - admins +complexity: intermediate +keywords: + - supabase migration + - supabase to kinde + - migrate from supabase + - supabase auth export + - supabase auth users + - user import + - password migration + - hashed passwords + - bcrypt + - csv import + - csv column mapping + - bulk import + - sql export + - social login migration +updated: 2026-05-05 +featured: false +deprecated: false +ai_summary: "Step-by-step guide for migrating users from Supabase Auth to Kinde using a bulk CSV import. Supabase stores passwords as bcrypt hashes in the auth.users table, which is not accessible via the standard API. Users are exported by running a SQL query in the Supabase SQL Editor — selecting id, email, encrypted_password, email_verified (derived from email_confirmed_at), and name fields from raw_user_meta_data. The exported CSV requires one column rename (encrypted_password to hashed_password) and a new hashing_method column set to bcrypt for every row. Social and OAuth users stored in auth.identities can be imported by email and will re-link their social login on first sign-in. The prepared CSV is imported in Kinde via Users > Import users > Custom CSV. Password authentication must be enabled in Kinde before importing hashed passwords. Links to the full bulk import guide for additional CSV fields covering organizations, roles, and permissions." +--- + +Migrate your users from Supabase Auth to Kinde. Supabase stores passwords as bcrypt hashes, and Kinde supports bcrypt natively — your users can sign in with their existing passwords with no reset required. + +### What you need + +- A Kinde account with **Admin** access +- Kinde account configured to match your current auth provider - see [before you migrate](/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication/#before-you-migrate) +- Supabase account with SQL editor permissions + +## Key considerations + +- **bcrypt passwords are fully supported** — Kinde imports bcrypt hashes directly. Users keep their existing password. +- **Export via SQL** — Supabase Auth data lives in the `auth.users` table, which isn't exposed via the standard API. You export users by running a SQL query in the Supabase dashboard. +- **Social/OAuth identities are separate** — users who signed in via Google, GitHub, etc. are stored in the `auth.identities` table. These users can be imported by email and will be prompted to re-link their social login on first sign-in. +- **`raw_user_meta_data` varies by app** — the structure of this field depends on what your app stores. Check it in the SQL editor before building your export query. + +## Migration guide + +### 1. Export users from Supabase + +1. Sign in to your [Supabase dashboard](https://app.supabase.com/) and select your project. +2. Go to **SQL Editor** in the sidebar. +3. Run the following query: + + ```sql + SELECT + id, + email, + encrypted_password AS hashed_password, + CASE WHEN email_confirmed_at IS NOT NULL THEN 'TRUE' ELSE 'FALSE' END AS email_verified, + raw_user_meta_data->>'first_name' AS first_name, + raw_user_meta_data->>'last_name' AS last_name + FROM auth.users + WHERE email IS NOT NULL; + ``` + +4. In the results panel, set the row limit to **No Limit** so all users are returned. +5. Select **Export** and choose **Download CSV**. + + + +### 2. Prepare the CSV for Kinde + +The SQL query exports columns that mostly match Kinde's expected names. Rename the one that differs and add the `hashing_method` column. + +| Supabase column | Rename to | Notes | +|---|---|---| +| `email` | `email` | Required — primary sign-in identifier | +| `id` | `id` | Keep as-is | +| `email_verified` | `email_verified` | Keep as-is — `TRUE` or `FALSE` | +| `first_name` | `first_name` | Keep as-is | +| `last_name` | `last_name` | Keep as-is | +| `encrypted_password` | `hashed_password` | bcrypt hash — preserves existing passwords | +| *(new column)* | `hashing_method` | Add this column and set every row to `bcrypt` | + +For the full list of supported CSV fields — including organizations, roles, and permissions — see [Prepare your CSV](/get-started/switch-to-kinde/migrate-users-bulk-import/#3-prepare-your-csv) in the bulk import guide. + + + +Your final CSV should look like this: + +```text +id,email,first_name,last_name,email_verified,hashed_password,hashing_method +abc-123,bills@company.com,Bill,Smith,TRUE,$2a$10$examplehash,bcrypt +def-456,carlosg@company.com,Carlos,Garcia,TRUE,$2a$10$examplehash,bcrypt +``` + +### 3. Import into Kinde + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Custom CSV**. +3. Follow the on-screen prompts to upload your file. +4. Review any errors reported after import. Fix the CSV and re-import to resolve them. + +See the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to learn more. + +### 4. Test the migration + +1. Sign in to Kinde with a user from your Supabase export. +2. Verify they can sign in with their existing Supabase credentials. +3. Notify users of any changes to their sign-in experience before going live. + +## Get support + +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) diff --git a/src/content/docs/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication.mdx b/src/content/docs/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication.mdx index 012ae1979..54a49d815 100644 --- a/src/content/docs/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication.mdx +++ b/src/content/docs/get-started/switch-to-kinde/switch-to-kinde-for-user-authentication.mdx @@ -3,184 +3,105 @@ page_id: c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d title: Migrate to Kinde for user authentication sidebar: order: 1 + label: Migration overview +tableOfContents: + maxHeadingLevel: 3 relatedArticles: - - 19438632-444e-44eb-bdb8-e99d2d88bcae - - 556c9ce6-477b-4a31-9ce1-75f612eb3740 + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc + - 98a6a913-a9ba-474c-8b01-6db706d08b4c + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 - e89d246a-5cdf-4993-9cee-94b31ec27583 -app_context: - - m: default - - m: login - - m: register -description: Comprehensive guide to migrating user authentication to Kinde including CSV import, password migration, authentication setup, and organizational configuration. +description: Overview of migration methods and provider guides for moving user authentication to Kinde. topics: - get-started - switch-to-kinde + - user-management + - authentication sdk: [] -languages: - - csv +languages: [] audience: - developers - admins - - business owners -complexity: advanced +complexity: intermediate keywords: - - user migration - - csv import - - password migration - - authentication methods - - organizations - - roles - - permissions - - hashing methods -updated: 2024-01-15 + - migrate users to kinde + - switch auth provider + - bulk import users + - drip feed migration + - api user creation + - auth0 to kinde + - clerk to kinde + - firebase to kinde + - supabase to kinde + - aws cognito to kinde + - azure b2c to kinde + - hashed password migration + - zero downtime migration + - user export +updated: 2026-05-05 featured: false deprecated: false -ai_summary: Comprehensive guide to migrating user authentication to Kinde including CSV import, password migration, authentication setup, and organizational configuration. +ai_summary: "This page is the top-level migration hub for teams moving user authentication to Kinde. It covers what data can be migrated — users, hashed passwords (bcrypt, sha256, md5, crypt, WordPress), organizations, and roles and permissions — and what to configure in Kinde before importing. It then presents four migration strategies: bulk import (export users to CSV or JSON and import in one go, with hashed password support), API-based user creation (provision users programmatically by intercepting sign-ins or sign-ups during a migration window), drip-feed migration (users migrate automatically on first login using a Kinde workflow that validates credentials against the legacy system — zero downtime, no bulk export needed, recommended for most teams), and hard cutover (planned maintenance window with a full export and import). Each strategy includes a best-for summary and a link to the detailed guide. The page also links to provider-specific export guides for Auth0, Clerk, Supabase, Firebase, AWS Cognito, and Azure B2C." --- -If you are currently using a different authentication tool to manage users, you can switch to Kinde pretty quickly. The method described here involves importing user details from CSV files into Kinde. [Follow this other guide](/get-started/switch-to-kinde/auth0-to-kinde/) if you are switching from Auth0. +Moving to Kinde from another auth provider? Choose a migration method below, then follow the export guide for your current provider. -If you’ve got a lot of users (your export file is over 5MB) or are concerned about file size limits, you can contact us to ensure the import goes smoothly. +## What you can migrate -## Before you import users +- **Users** — email, name, phone, external ID +- **Hashed passwords** — bcrypt, sha256, md5, crypt, wordpress supported +- **Organizations** — for multi-tenant apps +- **Roles and permissions** — assigned per user and per organization -- [Create organizations in Kinde](/build/organizations/add-and-manage-organizations/) - only if you use this function to support multi-tenancy (for example, in a B2B structure) or if you manage separate user groups this way. -- Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde, if you intend to import these details with users. +## Before you migrate -### Set up user authentication -We recommend setting up user authentication in Kinde before importing. For example, set up: +Set up the following in Kinde before importing users: -- Passwords - switch this option on before importing user passwords -- Passwordless - users will be sent a one-time code to sign in -- Social sign-on - users can sign up and in using Google, Apple, etc. -- Enterprise - SAML or Entra ID. +1. **Authentication methods** — enable [password authentication](/authenticate/authentication-methods/password-authentication/) if you're migrating passwords; enable [passwordless](/authenticate/authentication-methods/passwordless-authentication/) or social sign-on if users will need to re-authenticate. +2. **Organizations** — [create organizations in Kinde](/build/organizations/add-and-manage-organizations/) if you use multi-tenancy or separate user groups. +3. **Roles and permissions** — add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) before importing if you want to assign them to users on import. -**Note: Importing users from Azure** Set up the [MS Entra ID connection in Kinde](/authenticate/enterprise-connections/azure/) before you import your users. Then when you import, Kinde will match users to the relevant connection based on their email address. +## Choose your migration method -For more details, see [Authentication methods](/authenticate/authentication-methods/set-up-user-authentication/). +### Bulk import -## Step 1: Prepare user data +Export your users to a CSV or JSON file and import them into Kinde in one go. Works with hashed passwords — users keep their existing password with no reset required. -You can export user details and data fairly easily from most auth providers. However, some providers require you to separately request password details for users and this can take a little while. If you’re using your own auth system, prepare data as described below. +**Best for:** Teams doing a planned cutover with a defined migration window. -### File format +[Bulk import users →](/get-started/switch-to-kinde/migrate-users-bulk-import/) -User data can only be imported from a CSV file. Depending on what you currently use for auth, you will need to export or prepare data in a CSV file. +### Create users with the API -Kinde can import files up to 5MB. You may need to split the import into batches if you have a lot of users. +Provision users in Kinde programmatically during the migration window — for example, by intercepting sign-ups or sign-ins in your existing system and pushing them to Kinde in parallel. -### Export data from other systems or your own system +**Best for:** Catching new registrations and password changes during a migration window; teams with custom auth systems. -When exporting data from another auth system or your own system, the CSV file you export may need to be edited to ensure data is formatted in rows with some of these column headings. +[Create users with the API →](/get-started/switch-to-kinde/create-users-with-api/) -### Required **data** +### Drip-feed migration -- `email` - minimum required information -- `external_organization_id` - Only required if you are importing roles and permissions +Users migrate automatically as they log in. A Kinde workflow validates each login against your legacy system and creates the user in Kinde on first successful sign-in. No downtime. No bulk export required. - +### Hard cutover (maintenance window) -### **Other user data** +Take the service down, export all users, import into Kinde, then bring it back up. Simple, but requires planned downtime. -- `first_name` and `last_name` -- `id` (also referred to as `provided id`) - unique to the auth provider and helps us match records as they are imported. -- `phone` - including the international code with no spaces and no leading ‘0’, for example. +61555111555. Required for phone authentication. ([beta feature](https://kinde-21631392.hs-sites.com/en-au/beta-feature-interest)) -- `phone_verified` - phone number verification status: TRUE or FALSE ([beta feature](https://kinde-21631392.hs-sites.com/en-au/beta-feature-interest)) -- `email` - the user’s email address -- `email_verified` - email verification status: TRUE or FALSE -- `role_key` - the role key for the role a user will be assigned on import. If the user is to be assigned more than one role, use a comma separated list. -- `permission_key` - the permissions key for the permission a user will be assigned (that is not included in their role). If the user is to be assigned more than one permission, use a comma separated list. -- `external_organization_id` - the ID of the organizations you want the user to be imported into (if applicable). Only required if you are importing roles and permissions with user data. If the user belongs to more than one organization, use a comma separated list. +**Best for:** Small user bases where a short maintenance window is acceptable. - +Each provider has its own export format and limitations. Select your current provider for export steps and key considerations: -### Password data (optional) - -- `hashed_password` - the user’s password encrypted using a hashing method or algorithm. -- `hashing_method` - the name of the algorithm used to encrypt the user’s password. Currently **crypt**, **bcrypt**, **sha256**, **md5**, and **wordpress** are supported. [Contact us](https://kinde-21631392.hs-sites.com/en-au/feature-request) if you need a different method. -- `salt` - extra characters added to passwords to make them stronger -- `salt_position` - position of salt in password string. E.g. prefix (before) or suffix (after). -- `salt_format` - format of the salt, e.g. hex, string, etc. - - - - - - | Hashing method | Salt | Salt position | - | -------------- | -------- | ------------------------- | - | md5 | Optional | required if salt included | - | bcrypt | | | - | crypt | Optional | | - | wordpress | Optional | | - | sha256 | Optional | required if salt included | - -### Example CSV - -```text -email,first_name,last_name,email_verified,hashed_password,hashing_method,external_organization_id -bills@company.com,bill,smith,TRUE,#########,md5,abc001 -carlosg@company.com,carlos,garcia,TRUE,#########,md5,abc001 -lliu@company.com,lee,liu,FALSE,#########,md5,xyz002 -``` - -### Check for errors - -Before importing, check the CSV for missing information or duplication. Kinde will check for some errors during import, and report these back to you. - -### Passwords - -If you want your users to have an uninterrupted sign in experience as you change providers, you will need to bring their password data from your auth provider. Passwords are usually ‘hashed’ or encrypted so they cannot be read and they may be ‘salted’ as well (see above). - -If you decide not to import passwords, however, it’s not a big deal. Users will be prompted to reset their password or sign in using whatever authentication methods you have chosen to set up in Kinde. - -## Step 2: Import users - -Once you have your user details, you’re ready to import them. - -1. In Kinde, go to **Users**, then select **Import users**. -2. Select the **Import users** tab and then select **Import from a CSV** -3. Follow the on-screen prompts to upload the user data. -4. If there are any errors with the import, you will be able to view them afterwards. -5. Most import errors can be fixed by editing the CSV file and then re-importing into Kinde. Any records that have already been imported and have not been edited, will be ignored. - -For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). - -## After the migration - -### **Communication to users after import** - -Kinde does not send any notifications or invitations to users when they are added to Kinde via import. The idea is that your users have a seamless experience that feels (almost) like it always has in your app. - -Similarly, if you add users via API, Kinde does not send an email or notification to the user. - -If you’ve made changes to their sign in experience — for example adding multi-factor authentication — then consider contacting your users to let them know their sign in experience will be changed. - -### Additional consequences of migration - -Importing all your existing users and passwords following the above process should mean that your users won’t notice anything when they next sign in. This is the optimal experience. However: - -- If a user changes their password after the user export and while the migration is in progress, they will need to reset their password to sign in. -- If you have set up a new authentication method as part of the user migration (for instance, going password-less) your users will be prompted to use the new method on sign in. -- If you add or remove roles or permissions, users may gain/lose access to parts of your system. - -During and following the migration, we recommend checking for these issues. - -### There is no check for weak passwords - -When you import passwords, Kinde does not check for password strength. You’ll want to enforce your own password policies for users. +- [Auth0 →](/get-started/switch-to-kinde/auth0-to-kinde/) +- [Clerk →](/get-started/switch-to-kinde/clerk-to-kinde/) +- [Supabase →](/get-started/switch-to-kinde/supabase-to-kinde/) +- [Firebase →](/get-started/switch-to-kinde/firebase-to-kinde/) +- [AWS Cognito →](/get-started/switch-to-kinde/aws-cognito-to-kinde/) +- [Azure B2C →](/get-started/switch-to-kinde/azure-b2c-to-kinde/) diff --git a/src/content/docs/workflows/example-workflows/existing-password-provided-workflow.mdx b/src/content/docs/workflows/example-workflows/existing-password-provided-workflow.mdx index 729c69f9b..a95101ab6 100644 --- a/src/content/docs/workflows/example-workflows/existing-password-provided-workflow.mdx +++ b/src/content/docs/workflows/example-workflows/existing-password-provided-workflow.mdx @@ -24,10 +24,10 @@ keywords: - "password migration" - "drip feed migration" - "authentication triggers" -updated: "2025-01-27" +updated: "2026-05-04" featured: false deprecated: false -ai_summary: "Documentation for existing password provided workflow trigger that fires when users provide existing passwords, enabling validation against external databases and migration workflows." +ai_summary: "Explains the Kinde workflow trigger user:existing_password_provided, which fires after a user enters an existing password in the sign-in flow. The main pattern is drip-feed migration: call a legacy or external IdP or database to validate the credential, then create the user in Kinde and migrate the password only when checks pass. Security requirements: never rely on console logging for passwords (Kinde redacts them), and use the secureFetch binding for HTTP requests that include secrets so payloads are encrypted. Summarizes the workflow event—request (IP, user agent) and context with domains, auth (providedEmail, password, hashedPassword, hasUserRecordInKinde), optional user.id (notably in password-reset flows), and workflow.trigger. Covers the kinde.widget binding for invalidating the sign-in password field p_password via invalidateFormField. Cross-links the drip-feed migration tutorial (Auth0, AWS Cognito, Azure B2C), secureFetch documentation, and GitHub starter examples under existingPassword/." --- Trigger: `user:existing_password_provided` @@ -47,6 +47,8 @@ Security is at the heart of our technical decisions at Kinde, and keeping user p For gradual migrations to Kinde where you wish to check the password against an external database before creating the user in Kinde and migrating their password. [See example code](https://github.com/kinde-starter-kits/workflow-examples/blob/main/existingPassword/dripFeedMigrationWorkflow.ts) +For a complete step-by-step tutorial with provider-specific examples for Auth0, AWS Cognito, and Azure B2C, see the [Drip-feed migration tutorial](/workflows/workflow-tutorials/drip-feed-migration/). + ## Workflow code ### Sample event object diff --git a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx new file mode 100644 index 000000000..9fdb9fb6c --- /dev/null +++ b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx @@ -0,0 +1,462 @@ +--- +page_id: 0241b940-00bc-4ef0-b607-e70e388f4297 +title: Tutorial - Drip-feed user migration +sidebar: + order: 25 +tableOfContents: + maxHeadingLevel: 3 +relatedArticles: + - ca483387-5987-4449-a775-a9dfdedc0c7c + - f3dc6458-7d1e-407e-bc4c-62ac0ee4c075 + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - f6eaf29b-d8d9-4caf-bc1d-5319b6fb8ffc +description: Step-by-step tutorial for setting up a drip-feed user migration from any legacy auth system to Kinde using the user:existing_password_provided workflow trigger. +topics: + - workflows + - workflow-tutorials + - authentication + - user-management + - switch-to-kinde +sdk: kinde infrastructure +languages: + - TypeScript + - JavaScript +audience: + - developers +complexity: advanced +keywords: + - drip feed migration + - drip-feed migration + - progressive migration + - password migration workflow + - existing password workflow + - user:existing_password_provided + - zero downtime migration + - legacy auth migration + - Auth0 migration + - Cognito migration + - Azure B2C migration + - bulk import users + - enumeration protection + - secureFetch + - M2M API +updated: 2026-05-11 +featured: false +deprecated: false +ai_summary: "Step-by-step tutorial for progressively migrating users from a legacy auth system to Kinde using the user:existing_password_provided workflow trigger. Covers bulk-importing emails, enabling enumeration protection, setting up a Kinde M2M API and environment variables, and writing the migration workflow. Provides four ready-to-use workflow variants: a generic custom-backend version (with optional secureFetch encryption) and provider-specific versions for Auth0 (Resource Owner Password Flow), AWS Cognito (ADMIN_USER_PASSWORD_AUTH), and Azure B2C (ROPC). Includes deployment steps, end-to-end testing guidance, and instructions for decommissioning the legacy system once migration is complete." +--- + +Drip-feed migration lets you move users from your legacy auth system to Kinde progressively as they log in — no downtime, no forced password resets, and no bulk password export required. + +Each user is migrated the first time they sign in: Kinde validates their password against the legacy system, creates their account in Kinde, and takes over authentication from that point forward. Once all users have migrated naturally, you can decommission the legacy system. + +### What you need + +- A [Kinde account](/get-started/guides/first-things-first/) with **Admin** or **Engineer** access (Sign up for free) +- A workflow Git repository connected to your Kinde account - use the [workflow base template](/workflows/getting-started/quick-start-guide/) +- Your legacy auth system's password validation API (examples for Auth0, Cognito, and Azure B2C are provided below) + +## Step 1: Set up Kinde + +### 1. Bulk import emails into Kinde + +The `user:existing_password_provided` trigger only fires when the user's email already exists in Kinde. Run a [bulk import](/get-started/switch-to-kinde/migrate-users-bulk-import/) of user email addresses (without passwords) before enabling this workflow. Here is an example CSV format of your exported users: + +```text +# users.csv +email +user1@example.com +user2@example.com +user3@example.com +``` + +### 2. Enable Enumeration protection + +Go to your Kinde dashboard > **Settings > Environment > Attack protection > Enumeration protection** and turn it on. This is required for the workflow to function correctly. + +![Enumeration protection](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/9c36641e-c164-45ca-63f3-2aa7e6985d00/socialsharingimage) + +### 3. Setup a Kinde Management API + +This workflow updates the user password in Kinde, so you need to set up a Kinde Management API. + +1. Go to your Kinde dashboard > **Add new application** +2. Select **Machine to Machine** as the **Application type**, set a name (e.g., Drip feed migration app) +3. Select **Save** +4. Go to **APIs** in the side menu and select the **Three dots** next to the **Kinde Management API** and select **Authorize application**. +5. Select the **Three dots** again and select **Manage scopes**. +6. Enable the following scopes for your M2M app and select **Save**: + - `create:users` + - `update:user_passwords` +7. Go to the application **Details** page and copy the **Client ID** and **Client secret**. +8. Go to your Kinde dashboard > **Settings > Data management > Env variables** and set up the following variables with the values from the M2M application you created above: + - `KINDE_WF_M2M_CLIENT_ID` + - `KINDE_WF_M2M_CLIENT_SECRET` - Ensure this is setup with **Sensitive** flag enabled to prevent accidental sharing + +### 4. Set up additional environment variables + +You may need to add additional environment variables to your workflow, such as API URLs or config values. Follow these steps: + +1. Go to your Kinde dashboard > **Settings > Data management > Env variables** and add your environment variables. + +If you need to store a sensitive value, ensure it is set up with the **Sensitive** flag enabled to prevent accidental sharing. + +## Step 2: Set up the workflow + +### 1. Create the workflow + +1. Fork the [workflow base template](https://github.com/kinde-starter-kits/workflow-base-template) into your GitHub account by selecting **Use this template > Create a new repository**. + +2. Clone the repo: + + ```bash + git clone https://github.com/your_github_username/workflow-base-template.git + cd workflow-base-template + ``` + +3. Create a new workflow directory: + + ```bash + mkdir kindeSrc/environment/workflows/dripFeedMigration + touch kindeSrc/environment/workflows/dripFeedMigration/Workflow.ts + ``` + +4. Add the workflow code below. Choose the version for your legacy provider, or adapt the generic version for your own system. + +### 2A. Generic workflow (your custom backend) + +If you want to encrypt the password before sending it to your legacy system, use the `kinde.secureFetch` binding. However, if you don't need encryption, replace `kinde.secureFetch` with `kinde.fetch` — no encryption key is required. + +To use the secure fetch, follow the steps: + +1. Go to Workflows and select the Drip-feed migration workflow. +2. Select **Encryption keys** in the menu. +3. Select **Add encryption key**. A dialog appears, enabling you to copy the key. You need to copy it immediately, as it cannot be viewed again. +4. After you copy the key, select **Close**. If this is the first key you have added, it will automatically be made active. +5. Add the key to your code, to decrypt data sent from Kinde. + + Learn how to [Decrypt workflow‑encrypted payloads](/workflows/manage-workflows/encrypt-decrypt-workflows/#decrypt-workflowencrypted-payloads). + +6. Use the following code as a starting point if your legacy system has a custom password validation endpoint. + + ```typescript + import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, + } from "@kinde/infrastructure"; + + export const workflowSettings: WorkflowSettings = { + id: "dripFeedMigration", + name: "Drip-feed migration", + trigger: WorkflowTrigger.ExistingPasswordProvided, + failurePolicy: { action: "stop" }, + bindings: { + "kinde.fetch": {}, + "kinde.secureFetch": {}, + "url": {}, + }, + }; + + export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; + + // Already in Kinde — nothing to do + if (hasUserRecordInKinde) return; + + // Validate the password against your legacy system + const legacyResponse = await kinde.secureFetch("https://your-legacy-api.example.com/validate", { + method: "POST", + responseFormat: "json", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ email: providedEmail, password }), + }); + + if (!legacyResponse.ok) return; + + // Create user in Kinde and set their password + const kindeAPI = await createKindeAPI(event); + const { user } = await kindeAPI.post("/api/v1/user", { + profile: { email: providedEmail }, + identities: [{ type: "email", details: { email: providedEmail } }], + }); + + await kindeAPI.put(`/api/v1/users/${user.id}/password`, { + password, + is_temporary_password: false, + }); + } + ``` + +Check out the provider-specific variants below. + +### 2B. Auth0 variant + +1. Set the following [environment variables](/workflows/configuration/environment-variables-and-secrets/) in Kinde: + - `AUTH0_DOMAIN` + - `AUTH0_AUDIENCE` + - `AUTH0_CLIENT_ID` + - `AUTH0_CLIENT_SECRET` + +2. Use the following code to validate credentials using Auth0's Resource Owner Password Flow: + + ```typescript + import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, + getEnvironmentVariable, + } from "@kinde/infrastructure"; + + export const workflowSettings: WorkflowSettings = { + id: "dripFeedMigrationAuth0", + name: "Drip-feed migration (Auth0)", + trigger: WorkflowTrigger.ExistingPasswordProvided, + failurePolicy: { action: "stop" }, + bindings: { + "kinde.fetch": {}, + "kinde.env": {}, + "url": {}, + }, + }; + + export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; + + if (hasUserRecordInKinde) return; + + // Validate against Auth0 Resource Owner Password Flow + const auth0Domain = getEnvironmentVariable("AUTH0_DOMAIN")?.value; + const auth0Response = await kinde.fetch( + `https://${auth0Domain}/oauth/token`, + { + method: "POST", + responseFormat: "json", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + grant_type: "password", + username: providedEmail, + password, + audience: getEnvironmentVariable("AUTH0_AUDIENCE")?.value, + client_id: getEnvironmentVariable("AUTH0_CLIENT_ID")?.value, + client_secret: getEnvironmentVariable("AUTH0_CLIENT_SECRET")?.value, + }), + } + ); + + if (!auth0Response.ok) return; + + const kindeAPI = await createKindeAPI(event); + const { user } = await kindeAPI.post("/api/v1/user", { + profile: { email: providedEmail }, + identities: [{ type: "email", details: { email: providedEmail } }], + }); + + await kindeAPI.put(`/api/v1/users/${user.id}/password`, { + password, + is_temporary_password: false, + }); + } + ``` + +### 2C. AWS Cognito variant + +1. Set the following [environment variables](/workflows/configuration/environment-variables-and-secrets/) in Kinde: + - `AWS_REGION` + - `COGNITO_CLIENT_ID` + - `COGNITO_USER_POOL_ID` + +2. Uses Cognito's `ADMIN_USER_PASSWORD_AUTH` flow. Ensure this flow is enabled on your Cognito App Client before deploying. You will also need to sign the request with AWS Signature V4 — add your signing logic or use a Lambda proxy that handles auth. + +3. Use the following code in your workflow: + + ```typescript + import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, + getEnvironmentVariable, + } from "@kinde/infrastructure"; + + export const workflowSettings: WorkflowSettings = { + id: "dripFeedMigrationCognito", + name: "Drip-feed migration (Cognito)", + trigger: WorkflowTrigger.ExistingPasswordProvided, + failurePolicy: { action: "stop" }, + bindings: { + "kinde.fetch": {}, + "kinde.env": {}, + "url": {}, + }, + }; + + export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; + + if (hasUserRecordInKinde) return; + + // Validate against Cognito ADMIN_USER_PASSWORD_AUTH + const awsRegion = getEnvironmentVariable("AWS_REGION")?.value; + const cognitoResponse = await kinde.fetch( + `https://cognito-idp.${awsRegion}.amazonaws.com/`, + { + method: "POST", + responseFormat: "json", + headers: { + "Content-Type": "application/x-amz-json-1.1", + "X-Amz-Target": "AWSCognitoIdentityProviderService.AdminInitiateAuth", + }, + body: JSON.stringify({ + AuthFlow: "ADMIN_USER_PASSWORD_AUTH", + ClientId: getEnvironmentVariable("COGNITO_CLIENT_ID")?.value, + UserPoolId: getEnvironmentVariable("COGNITO_USER_POOL_ID")?.value, + AuthParameters: { + USERNAME: providedEmail, + PASSWORD: password, + }, + }), + } + ); + + if (!cognitoResponse.ok) return; + + const kindeAPI = await createKindeAPI(event); + const { user } = await kindeAPI.post("/api/v1/user", { + profile: { email: providedEmail }, + identities: [{ type: "email", details: { email: providedEmail } }], + }); + + await kindeAPI.put(`/api/v1/users/${user.id}/password`, { + password, + is_temporary_password: false, + }); + } + ``` + +### 2D. Azure B2C variant + +1. Set the following [environment variables](/workflows/configuration/environment-variables-and-secrets/) in Kinde: + - `AZURE_B2C_TENANT` + - `AZURE_B2C_ROPC_POLICY` + - `AZURE_B2C_CLIENT_ID` + - `AZURE_B2C_SCOPE` + +2. Uses the Azure B2C Resource Owner Password Credentials (ROPC) token endpoint. Use the following code in your workflow: + + ```typescript + import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, + getEnvironmentVariable, + } from "@kinde/infrastructure"; + + export const workflowSettings: WorkflowSettings = { + id: "dripFeedMigrationAzureB2C", + name: "Drip-feed migration (Azure B2C)", + trigger: WorkflowTrigger.ExistingPasswordProvided, + failurePolicy: { action: "stop" }, + bindings: { + "kinde.fetch": {}, + "kinde.env": {}, + "url": {}, + }, + }; + + export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; + + if (hasUserRecordInKinde) return; + + const tenant = getEnvironmentVariable("AZURE_B2C_TENANT")?.value; + const policy = getEnvironmentVariable("AZURE_B2C_ROPC_POLICY")?.value; + const clientId = getEnvironmentVariable("AZURE_B2C_CLIENT_ID")?.value; + const scope = getEnvironmentVariable("AZURE_B2C_SCOPE")?.value; + + const body = new URLSearchParams({ + grant_type: "password", + client_id: clientId, + scope: `openid ${scope}`, + username: providedEmail, + password, + response_type: "token", + }); + + const azureResponse = await kinde.fetch( + `https://${tenant}.b2clogin.com/${tenant}.onmicrosoft.com/${policy}/oauth2/v2.0/token`, + { + method: "POST", + responseFormat: "json", + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + body: body.toString(), + } + ); + + if (!azureResponse.ok) return; + + const kindeAPI = await createKindeAPI(event); + const { user } = await kindeAPI.post("/api/v1/user", { + profile: { email: providedEmail }, + identities: [{ type: "email", details: { email: providedEmail } }], + }); + + await kindeAPI.put(`/api/v1/users/${user.id}/password`, { + password, + is_temporary_password: false, + }); + } + ``` + +### 3. Push your workflow code to GitHub + + ```bash + git add . + git commit -m "add drip-feed migration workflow" + git push + ``` + +## Step 3: Test the drip-feed migration + +### 1. Deploy the workflow + +1. Sign in to your [Kinde dashboard](https://kinde.com/) and select **Workflows** from the sidebar. +2. If you haven't connected a repo yet, select **Connect repo > Connect GitHub** and follow the prompts. +3. Select your repository, choose the `main` branch, and select **Next**. +4. Select **Sync code** to pull your workflow into Kinde. You'll see it listed in the dashboard. + +For full deployment instructions, see [Manage code and deployments](/workflows/manage-workflows/manage-code-and-deployments/). + +### 2. Connect Kinde to your application + +1. Create an application and connect your codebase by [following these instructions](/get-started/guides/byo-code/). +2. Go to **Authentication**. +3. Enable **Email + password** if it isn't already enabled. +4. Select **Save**. + +### 3. Test the migration + +1. Run your application and navigate to the login page. +2. Sign in as a test user (one who exists in your legacy system but not yet fully in Kinde). +3. Confirm the user is logged in to your application with their legacy credentials. +4. Go to Kinde dashboard > **Users** and confirm the user appears in the list. +5. Go to Kinde > **Workflows** and select the **Drip-feed migration** workflow. +6. Select **Runtime logs** to troubleshoot any workflow issues. +7. Sign in as the same user a second time — they should authenticate directly through Kinde this time. + +### 4. Decommission your legacy system + +Once the drip-feed is running: + +- Monitor sign-in volume on your legacy system over time. +- When new validations drop to zero (all active users have migrated), remove or disable the workflow. +- Decommission your legacy auth system. + +Users who never logged in during the migration period will not be migrated. Decide whether to keep inactive users (force a password reset via [the API](/get-started/switch-to-kinde/create-users-with-api/)) or remove them. + +## Get support + +If you need help with your migration, contact [Kinde support](https://kinde.com/support). \ No newline at end of file