From d893466b09f6877b96c7ae5e8f324c83f8d0e51e Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 28 Apr 2026 22:32:55 +0600 Subject: [PATCH 01/14] initial clerk migration guide --- .../switch-to-kinde/auth0-to-kinde.mdx | 1 + .../switch-to-kinde/clerk-to-kinde.mdx | 151 ++++++++++++++++++ .../switch-to-kinde/firebase-to-kinde.mdx | 145 +++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx create mode 100644 src/content/docs/get-started/switch-to-kinde/firebase-to-kinde.mdx 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..a413cf489 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,6 +3,7 @@ page_id: b338980f-7dd6-4ba5-90aa-330247a45536 title: Migrate to Kinde from Auth0 sidebar: order: 2 + label: Auth0 relatedArticles: - e89d246a-5cdf-4993-9cee-94b31ec27583 - d9980c1a-71c8-4fe9-8433-4ff09c9fe6ee 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..7efe8f7cc --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx @@ -0,0 +1,151 @@ +--- +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 + - b338980f-7dd6-4ba5-90aa-330247a45536 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Step-by-step guide to migrating users and hashed passwords from Clerk to Kinde, including how to export user data and import it into Kinde. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - csv +audience: + - developers + - admins +complexity: advanced +keywords: + - clerk migration + - clerk to kinde + - user import + - password migration + - hashed passwords + - csv import +updated: 2026-04-28 +featured: false +deprecated: false +ai_summary: Step-by-step guide to migrating users and hashed passwords from Clerk to Kinde, including how to export user data and import it into Kinde. +--- + +Migrate your users from Clerk to Kinde. The process involves contacting Clerk support to get the export, preparing the data, and importing into Kinde. + +Clerk supports exporting user data including hashed passwords, which means your users can migrate without needing to reset their passwords. + +## Clerk migration guide + +### 1. Export users from Clerk + +1. Sign in to your [Clerk dashboard](https://dashboard.clerk.com/). +2. Select your application. +3. Go to **Configure > Settings**. +4. Under the **User exports** select, **Export users**. +5. When the export is ready, select **Download**. It will download a CSV file. + +Clerk's documentation on [exporting users from Clerk](https://clerk.com/docs/guides/development/migrating/overview#export-your-users-data-from-the-clerk-dashboard). + +### ?. Import users into Kinde + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select the **Import users** tab, then select **Import from a CSV**. +3. Follow the on-screen prompts to upload your file. +4. If there are errors, view them after the import, fix the CSV, and re-import. + +For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). + +**Importing passwords separately:** + +If you imported users first and want to add passwords in a second pass: + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select the **Import users** tab and choose to update existing users by re-importing the same emails with the password columns included. + +## Prepare your Kinde business + +Configure your Kinde business to match or improve on your current Clerk setup. + +1. Register for a Kinde account and [finish the onboarding process](/get-started/guides/first-things-first/) if you haven't already. +2. Set up [authentication methods](/authenticate/about-auth/about-authentication/) to match your current Clerk setup. + - **Password** — enable this before importing password hashes so users can sign in without resetting + - **Passwordless** — one-time code via email or SMS + - **Social sign-on** — Google, Apple, GitHub, Microsoft, and more + - **Enterprise** — SAML or Microsoft Entra ID +3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (e.g. a B2B app). +4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde if you plan to import these alongside users. + +## Prepare your user CSV + +Kinde imports users from a CSV file. If Clerk provides a JSON export, you'll need to convert it to CSV format. Structure the file with these columns. + +### Required columns + +| Column | Notes | +|--------|-------| +| `email` | Minimum required field | + +### Recommended columns + +| Column | Notes | +|--------|-------| +| `first_name`, `last_name` | User's name | +| `email_verified` | `TRUE` or `FALSE` | +| `id` | Clerk user ID — helps match records during import | +| `phone` | International format, e.g. `+61555111555` | +| `external_organization_id` | Organization ID to import the user into (if applicable) | +| `role_key` | Role key(s) to assign; comma-separate multiple values | +| `permission_key` | Permission key(s) to assign; comma-separate multiple values | + +### Password columns (if importing hashed passwords) + +| Column | Notes | +|--------|-------| +| `hashed_password` | The user's password encrypted with a hashing algorithm | +| `hashing_method` | The algorithm used — Kinde supports `bcrypt`, `sha256`, `md5`, `crypt`, `wordpress` | +| `salt` | Extra characters added to passwords (if applicable) | +| `salt_position` | `prefix` or `suffix` (required if salt is included) | +| `salt_format` | Format of the salt, e.g. `hex` or `string` | + + + + + +### Example CSV (with passwords) + +```text +email,first_name,last_name,email_verified,id,hashed_password,hashing_method +alice@example.com,Alice,Smith,TRUE,clerk_uid_abc123,#########,bcrypt +bob@example.com,Bob,Jones,TRUE,clerk_uid_xyz789,#########,bcrypt +``` + +### Example CSV (without passwords) + +```text +email,first_name,last_name,email_verified,id +alice@example.com,Alice,Smith,TRUE,clerk_uid_abc123 +bob@example.com,Bob,Jones,FALSE,clerk_uid_xyz789 +``` + +### Check for errors before importing + +Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes will be skipped. + + + +## Next steps + +- Notify your users of the change before going live, especially if they’ll experience a different sign-in flow. +- Verify users are able to sign in with their existing password to Kinde. 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..ee08d9803 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/firebase-to-kinde.mdx @@ -0,0 +1,145 @@ +--- +page_id: f2a8d3e6-7c14-4b09-a5e1-3d8c7f29b045 +title: Migrate to Kinde from Firebase Authentication +sidebar: + order: 4 + label: Firebase +relatedArticles: + - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d + - b338980f-7dd6-4ba5-90aa-330247a45536 + - e89d246a-5cdf-4993-9cee-94b31ec27583 +description: Step-by-step guide to migrating users from Firebase Authentication to Kinde, including export options, SCRYPT password limitations, and alternative sign-in strategies. +topics: + - get-started + - switch-to-kinde +sdk: [] +languages: + - bash + - csv +audience: + - developers + - admins +complexity: advanced +keywords: + - firebase migration + - firebase authentication + - user import + - scrypt + - password migration + - csv import +updated: 2026-04-28 +featured: false +deprecated: false +ai_summary: Step-by-step guide to migrating users from Firebase Authentication to Kinde, including export options, SCRYPT password limitations, and alternative sign-in strategies. +--- + +This guide walks you through migrating your users from Firebase Authentication to Kinde. + +The key thing to know upfront: Firebase uses the **SCRYPT** hashing algorithm for passwords, which Kinde does not currently support for import. If you're switching to passwordless or social sign-on, this isn't a problem — you can import users without passwords and they'll use the new auth method on first sign-in. If seamless password continuity is critical, read the [password section below](#can-i-migrate-passwords-from-firebase) before proceeding. + +### What you need + +- A [Kinde account](https://kinde.com/) (sign up for free) +- Access to your Firebase project and the [Firebase CLI](https://firebase.google.com/docs/cli) installed +- Your user data exported from Firebase (instructions below) + +## Step 1: Prepare your Kinde business + +Before importing users, set up Kinde so it's ready to receive them. + +1. [Register for a Kinde account](https://app.kinde.com/register) if you haven't already (no credit card required). +2. Set up [authentication methods](/authenticate/about-auth/about-authentication/) — choose what users will sign in with after the migration: + - **Passwordless** — users get a one-time code on sign-in (recommended if password import isn't possible) + - **Social sign-on** — Google, Apple, GitHub, etc. + - **Password** — enable this if you plan to ask users to set a new password on first sign-in + - **Enterprise** — SAML or Microsoft Entra ID +3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (B2B apps). +4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) if you plan to import those with users. + +## Step 2: Export users from Firebase + +Firebase provides a CLI command to export your authentication users. + +```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). + +### Can I migrate passwords from Firebase? + +No — not currently. Firebase uses the **SCRYPT** hashing algorithm, which Kinde does not currently support for password import. + +Your options are: + +- **Import users without passwords** — users are prompted to reset their password or sign in using your chosen auth method (passwordless, social, etc.) on first login. This is the most common path. +- **Request SCRYPT support** — if password continuity is critical for your use case, [submit a feature request](https://kinde-21631392.hs-sites.com/en-au/feature-request) so we can prioritise it. + +We recommend setting up passwordless or social sign-on in Kinde before migration, so users have a smooth path to sign in even without a migrated password. + +## Step 3: Prepare your user CSV + +Kinde imports users from a CSV file. Convert your Firebase export into the format below. + +### Required columns + +| Column | Notes | +|--------|-------| +| `email` | Minimum required field | + +### Recommended columns + +| Column | Notes | +|--------|-------| +| `first_name`, `last_name` | User's name | +| `email_verified` | `TRUE` or `FALSE` | +| `id` | Firebase UID — helps match records during import | +| `phone` | International format, e.g. `+61555111555` | +| `external_organization_id` | ID of the organization to import the user into (if applicable) | +| `role_key` | Role key(s) to assign; comma-separate multiple values | +| `permission_key` | Permission key(s) to assign; comma-separate multiple values | + + + +### Example CSV + +```text +email,first_name,last_name,email_verified,id +alice@example.com,Alice,Smith,TRUE,firebase-uid-abc123 +bob@example.com,Bob,Jones,FALSE,firebase-uid-xyz789 +``` + +### Check for errors before importing + +Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back to you. + +## Step 4: Import users into Kinde + +1. In Kinde, go to **Users**, then select **Import users**. +2. Select the **Import users** tab, then select **Import from a CSV**. +3. Follow the on-screen prompts to upload your file. +4. After import, review any flagged errors. Fix the CSV and re-import — records already imported without changes will be skipped. + +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 + +Kinde does not send notifications or invitations when users are added via import. Because Firebase SCRYPT passwords cannot be migrated, users will need to reset their password or sign in using a new method on their first Kinde login. + +Notify your users of the change before going live, especially if they'll experience a different sign-in flow. + +### Additional consequences of migration + +- Users will be prompted to reset their password or use an alternative auth method on first sign-in (passwords are not migrated from Firebase). +- If you've set up new auth methods (e.g. social sign-on or passwordless), configure these in Kinde before migration so users have options at sign-in. +- If you add or remove roles or permissions, users may gain or lose access to parts of your system. + +### There is no check for weak passwords + +When users set a new password in Kinde, password strength is not checked against Firebase's previous rules. Enforce your own password policies as needed. From 0094f667a11f4435655a08db386b160263d11b3b Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Wed, 29 Apr 2026 00:01:12 +0600 Subject: [PATCH 02/14] created the clerk migration guide --- .../switch-to-kinde/clerk-to-kinde.mdx | 121 ++++++++---------- 1 file changed, 52 insertions(+), 69 deletions(-) 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 index 7efe8f7cc..4d5739f1f 100644 --- 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 @@ -14,6 +14,9 @@ description: Step-by-step guide to migrating users and hashed passwords from Cle topics: - get-started - switch-to-kinde +app_context: + - m: users + - s: list sdk: [] languages: - csv @@ -24,72 +27,55 @@ complexity: advanced keywords: - clerk migration - clerk to kinde + - migrate from clerk - user import - password migration - hashed passwords - csv import + - authentication migration + - clerk export updated: 2026-04-28 featured: false deprecated: false -ai_summary: Step-by-step guide to migrating users and hashed passwords from Clerk to Kinde, including how to export user data and import it into Kinde. +ai_summary: "This guide walks through migrating users from Clerk to Kinde in five steps. Because Clerk supports exporting hashed passwords, migrated users can sign in with their existing passwords without a forced reset. First, export users from the Clerk dashboard as a CSV. Second, prepare the CSV by mapping columns to Kinde's format — the only required field is `email`, but you can also include `hashed_password` and `hashing_method` (bcrypt, sha256, md5, crypt, or wordpress), plus recommended fields like `first_name`, `last_name`, `email_verified`, `id`, `phone`, `external_organization_id`, `role_key`, and `permission_key`. Third, set up your Kinde business by enabling authentication methods, creating organizations, and defining roles and permissions before importing. Fourth, import the CSV via Users > Import users > Custom CSV. Fifth, test the migration by signing in with a migrated user. Review the CSV for errors before importing — Kinde reports issues and skips already-imported records on re-import. After migration, notify users of any changes to their sign-in experience." --- -Migrate your users from Clerk to Kinde. The process involves contacting Clerk support to get the export, preparing the data, and importing into Kinde. +Migrate your users from Clerk to Kinde. The process involves exporting user data from the Clerk dashboard, preparing the CSV, and importing it into Kinde. -Clerk supports exporting user data including hashed passwords, which means your users can migrate without needing to reset their passwords. +Clerk supports exporting hashed passwords out of the box, so your migrated users can sign in with their existing passwords without having to reset them. -## Clerk migration guide +## Migration guide ### 1. Export users from Clerk -1. Sign in to your [Clerk dashboard](https://dashboard.clerk.com/). -2. Select your application. +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 the **User exports** select, **Export users**. +4. Under the **User exports** section, select **Export users**. 5. When the export is ready, select **Download**. It will download a CSV file. -Clerk's documentation on [exporting users from Clerk](https://clerk.com/docs/guides/development/migrating/overview#export-your-users-data-from-the-clerk-dashboard). +![Clerk export users](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/466e727b-0a72-4475-a019-4a685579a200/socialsharingimage) -### ?. Import users into Kinde +See Clerk's documentation on [exporting users](https://clerk.com/docs/guides/development/migrating/overview#export-your-users-data-from-the-clerk-dashboard). -1. In Kinde, go to **Users**, then select **Import users**. -2. Select the **Import users** tab, then select **Import from a CSV**. -3. Follow the on-screen prompts to upload your file. -4. If there are errors, view them after the import, fix the CSV, and re-import. - -For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). - -**Importing passwords separately:** +### 2. Prepare your user CSV -If you imported users first and want to add passwords in a second pass: +Modify your Clerk CSV columns to match the supported columns by Kinde: -1. In Kinde, go to **Users**, then select **Import users**. -2. Select the **Import users** tab and choose to update existing users by re-importing the same emails with the password columns included. - -## Prepare your Kinde business +**Required columns:** -Configure your Kinde business to match or improve on your current Clerk setup. - -1. Register for a Kinde account and [finish the onboarding process](/get-started/guides/first-things-first/) if you haven't already. -2. Set up [authentication methods](/authenticate/about-auth/about-authentication/) to match your current Clerk setup. - - **Password** — enable this before importing password hashes so users can sign in without resetting - - **Passwordless** — one-time code via email or SMS - - **Social sign-on** — Google, Apple, GitHub, Microsoft, and more - - **Enterprise** — SAML or Microsoft Entra ID -3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (e.g. a B2B app). -4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde if you plan to import these alongside users. - -## Prepare your user CSV - -Kinde imports users from a CSV file. If Clerk provides a JSON export, you'll need to convert it to CSV format. Structure the file with these columns. +| Column | Notes | +|--------|-------| +| `email` | Minimum required field | -### Required columns +**Password columns (if importing hashed passwords):** | Column | Notes | |--------|-------| -| `email` | Minimum required field | +| `hashed_password` | The user's password encrypted with a hashing algorithm | +| `hashing_method` | Kinde supports `bcrypt`, `sha256`, `md5`, `crypt`, `wordpress` | -### Recommended columns +**Recommended columns:** | Column | Notes | |--------|-------| @@ -101,51 +87,48 @@ Kinde imports users from a CSV file. If Clerk provides a JSON export, you'll nee | `role_key` | Role key(s) to assign; comma-separate multiple values | | `permission_key` | Permission key(s) to assign; comma-separate multiple values | -### Password columns (if importing hashed passwords) - -| Column | Notes | -|--------|-------| -| `hashed_password` | The user's password encrypted with a hashing algorithm | -| `hashing_method` | The algorithm used — Kinde supports `bcrypt`, `sha256`, `md5`, `crypt`, `wordpress` | -| `salt` | Extra characters added to passwords (if applicable) | -| `salt_position` | `prefix` or `suffix` (required if salt is included) | -| `salt_format` | Format of the salt, e.g. `hex` or `string` | - - +1. Register for a Kinde account and [finish the onboarding process](/get-started/guides/first-things-first/) if you haven't already. +2. Set up [authentication methods](/authenticate/authentication-methods/set-up-user-authentication/) to match your current Clerk setup. + - **Password** — enable this before importing password hashes so users can sign in without resetting + - **Passwordless** — one-time code via email or SMS + - **Social sign-on** — Google, Apple, GitHub, Microsoft, and more + - **Enterprise** — SAML or Microsoft Entra ID +3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (e.g. a B2B app). +4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde if you plan to import these alongside users. -### Example CSV (with passwords) -```text -email,first_name,last_name,email_verified,id,hashed_password,hashing_method -alice@example.com,Alice,Smith,TRUE,clerk_uid_abc123,#########,bcrypt -bob@example.com,Bob,Jones,TRUE,clerk_uid_xyz789,#########,bcrypt -``` +### 4. Import users into Kinde -### Example CSV (without passwords) +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Custom CSV**, then select **Next**. +3. Select the CSV file you prepared and select **Import**. -```text -email,first_name,last_name,email_verified,id -alice@example.com,Alice,Smith,TRUE,clerk_uid_abc123 -bob@example.com,Bob,Jones,FALSE,clerk_uid_xyz789 -``` + After the import, you will find the list of users in the **Users** tab. -### Check for errors before importing + For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). -Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes will be skipped. +### 5. Test the migration + +1. Run your Kinde application. +2. Sign in with a test user you migrated. +3. Verify you can sign in with the test user. +## Troubleshooting +**Check for errors before importing:** + +Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes will be skipped. ## Next steps - Notify your users of the change before going live, especially if they’ll experience a different sign-in flow. -- Verify users are able to sign in with their existing password to Kinde. +- Verify users are able to sign in to Kinde with their existing Clerk login methods. From 37f14212ced5a27aaaea9bb696e8958c731b0404 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Wed, 29 Apr 2026 00:54:20 +0600 Subject: [PATCH 03/14] add firebase migration guide --- .../switch-to-kinde/firebase-to-kinde.mdx | 104 +++++++----------- 1 file changed, 41 insertions(+), 63 deletions(-) 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 index ee08d9803..e7fd84958 100644 --- 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 @@ -4,6 +4,8 @@ title: Migrate to Kinde from Firebase Authentication sidebar: order: 4 label: Firebase +tableOfContents: + maxHeadingLevel: 3 relatedArticles: - c4bc277a-5ec7-418c-ba1c-4d58c9ddfd7d - b338980f-7dd6-4ba5-90aa-330247a45536 @@ -23,42 +25,28 @@ complexity: advanced keywords: - firebase migration - firebase authentication + - migrate from firebase + - firebase export - user import - scrypt - password migration - csv import + - authentication migration updated: 2026-04-28 featured: false deprecated: false -ai_summary: Step-by-step guide to migrating users from Firebase Authentication to Kinde, including export options, SCRYPT password limitations, and alternative sign-in strategies. +ai_summary: "This guide covers migrating users from Firebase Authentication to Kinde in five steps. The critical limitation to know upfront: Firebase uses SCRYPT password hashing, which Kinde does not currently support for import — users will need to reset their password or sign in via a new method on first login. First, export users from Firebase using the CLI command `firebase auth:export users.json --format=json`, which exports emails, display names, UIDs, and hashed passwords. Second, convert the export to a Kinde-compatible CSV — the only required field is `email`, with recommended fields including `first_name`, `last_name`, `email_verified`, and `id` (Firebase UID). Third, set up your Kinde business by enabling authentication methods suited for your users — passwordless is recommended given the password limitation. Fourth, import the CSV via Users > Import users > Custom CSV. Fifth, test by signing in with a migrated user. Before going live, notify users they will need to use a new sign-in method since Firebase passwords cannot be carried over." --- -This guide walks you through migrating your users from Firebase Authentication to Kinde. +Migrate your users from Firebase Authentication to Kinde. The process involves exporting user data from Firebase, preparing the CSV, and importing it into Kinde. -The key thing to know upfront: Firebase uses the **SCRYPT** hashing algorithm for passwords, which Kinde does not currently support for import. If you're switching to passwordless or social sign-on, this isn't a problem — you can import users without passwords and they'll use the new auth method on first sign-in. If seamless password continuity is critical, read the [password section below](#can-i-migrate-passwords-from-firebase) before proceeding. +The key limitation to know upfront: Firebase uses the `SCRYPT` hashing algorithm for passwords, which Kinde does not currently support for import. If you're switching to passwordless or social sign-on, this isn't a problem — import users without passwords and they'll use the new auth method on first sign-in. If password continuity is critical, [submit a feature request](https://updates.kinde.com/) to prioritize SCRYPT support. -### What you need +## Migration guide -- A [Kinde account](https://kinde.com/) (sign up for free) -- Access to your Firebase project and the [Firebase CLI](https://firebase.google.com/docs/cli) installed -- Your user data exported from Firebase (instructions below) +### 1. Export users from Firebase -## Step 1: Prepare your Kinde business - -Before importing users, set up Kinde so it's ready to receive them. - -1. [Register for a Kinde account](https://app.kinde.com/register) if you haven't already (no credit card required). -2. Set up [authentication methods](/authenticate/about-auth/about-authentication/) — choose what users will sign in with after the migration: - - **Passwordless** — users get a one-time code on sign-in (recommended if password import isn't possible) - - **Social sign-on** — Google, Apple, GitHub, etc. - - **Password** — enable this if you plan to ask users to set a new password on first sign-in - - **Enterprise** — SAML or Microsoft Entra ID -3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (B2B apps). -4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) if you plan to import those with users. - -## Step 2: Export users from Firebase - -Firebase provides a CLI command to export your authentication users. +Make sure you have the [Firebase CLI](https://firebase.google.com/docs/cli) installed, then run: ```bash firebase auth:export users.json --format=json @@ -66,28 +54,17 @@ 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). -### Can I migrate passwords from Firebase? - -No — not currently. Firebase uses the **SCRYPT** hashing algorithm, which Kinde does not currently support for password import. - -Your options are: +### 2. Prepare your user CSV -- **Import users without passwords** — users are prompted to reset their password or sign in using your chosen auth method (passwordless, social, etc.) on first login. This is the most common path. -- **Request SCRYPT support** — if password continuity is critical for your use case, [submit a feature request](https://kinde-21631392.hs-sites.com/en-au/feature-request) so we can prioritise it. +Convert your Firebase JSON export into a CSV using the format below. Remove the password related columns from the CSV, so your users will be prompted to set a new password on first sign-in. -We recommend setting up passwordless or social sign-on in Kinde before migration, so users have a smooth path to sign in even without a migrated password. - -## Step 3: Prepare your user CSV - -Kinde imports users from a CSV file. Convert your Firebase export into the format below. - -### Required columns +**Required columns:** | Column | Notes | |--------|-------| | `email` | Minimum required field | -### Recommended columns +**Recommended columns:** | Column | Notes | |--------|-------| @@ -95,7 +72,7 @@ Kinde imports users from a CSV file. Convert your Firebase export into the forma | `email_verified` | `TRUE` or `FALSE` | | `id` | Firebase UID — helps match records during import | | `phone` | International format, e.g. `+61555111555` | -| `external_organization_id` | ID of the organization to import the user into (if applicable) | +| `external_organization_id` | Organization ID to import the user into (if applicable) | | `role_key` | Role key(s) to assign; comma-separate multiple values | | `permission_key` | Permission key(s) to assign; comma-separate multiple values | @@ -105,41 +82,42 @@ Kinde will not duplicate users with existing email addresses. If a user already -### Example CSV +### 3. Prepare your Kinde business -```text -email,first_name,last_name,email_verified,id -alice@example.com,Alice,Smith,TRUE,firebase-uid-abc123 -bob@example.com,Bob,Jones,FALSE,firebase-uid-xyz789 -``` - -### Check for errors before importing +Configure your Kinde business to match or improve on your current Firebase setup. -Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back to you. +1. Register for a Kinde account and [finish the onboarding process](/get-started/guides/first-things-first/) if you haven't already. +2. Set up [authentication methods](/authenticate/authentication-methods/set-up-user-authentication/) to match your current Firebase setup. Since Firebase passwords cannot be imported, we recommend enabling at least one passwordless option: + - **Passwordless** — one-time code via email or SMS (recommended) + - **Social sign-on** — Google, Apple, GitHub, Microsoft, and more + - **Password** — enable if you plan to have users set a new password on first sign-in + - **Enterprise** — SAML or Microsoft Entra ID +3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (e.g. a B2B app). +4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde if you plan to import these alongside users. -## Step 4: Import users into Kinde +### 4. Import users into Kinde 1. In Kinde, go to **Users**, then select **Import users**. -2. Select the **Import users** tab, then select **Import from a CSV**. -3. Follow the on-screen prompts to upload your file. -4. After import, review any flagged errors. Fix the CSV and re-import — records already imported without changes will be skipped. +2. Select **Custom CSV**, then select **Next**. +3. Select the CSV file you prepared and select **Import**. -For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). + After the import, you will find the list of users in the **Users** tab. -## After the migration + For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). -### Communication to users +### 5. Test the migration -Kinde does not send notifications or invitations when users are added via import. Because Firebase SCRYPT passwords cannot be migrated, users will need to reset their password or sign in using a new method on their first Kinde login. +1. Run your Kinde application. +2. Sign in with a test user you migrated. +3. Verify you can sign in using passwordless, social, or password reset — whichever method you configured. -Notify your users of the change before going live, especially if they'll experience a different sign-in flow. +## Troubleshooting -### Additional consequences of migration +**Check for errors before importing:** -- Users will be prompted to reset their password or use an alternative auth method on first sign-in (passwords are not migrated from Firebase). -- If you've set up new auth methods (e.g. social sign-on or passwordless), configure these in Kinde before migration so users have options at sign-in. -- If you add or remove roles or permissions, users may gain or lose access to parts of your system. +Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes will be skipped. -### There is no check for weak passwords +## Next steps -When users set a new password in Kinde, password strength is not checked against Firebase's previous rules. Enforce your own password policies as needed. +- Notify your users of the change before going live — since Firebase passwords cannot be migrated, they'll need to sign in using a new method. +- Verify users are able to sign in to Kinde using the authentication methods you configured. From 3e0e6c6e0926767cfcb4ca194e737018b78d5d92 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Wed, 29 Apr 2026 00:56:13 +0600 Subject: [PATCH 04/14] fix coderabbit suggestion --- src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 4d5739f1f..d01f6135e 100644 --- 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 @@ -72,7 +72,7 @@ Modify your Clerk CSV columns to match the supported columns by Kinde: | Column | Notes | |--------|-------| -| `hashed_password` | The user's password encrypted with a hashing algorithm | +| `hashed_password` | The user's password hashed with a hashing algorithm | | `hashing_method` | Kinde supports `bcrypt`, `sha256`, `md5`, `crypt`, `wordpress` | **Recommended columns:** From 73745f8735a3181c5fd374b29349c504f6feb242 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 5 May 2026 15:56:37 +0600 Subject: [PATCH 05/14] update with new outline --- .../switch-to-kinde/auth0-to-kinde.mdx | 195 +++++----- .../switch-to-kinde/aws-cognito-to-kinde.mdx | 101 +++++ .../switch-to-kinde/azure-b2c-to-kinde.mdx | 133 +++++++ .../switch-to-kinde/clerk-to-kinde.mdx | 91 ++--- .../switch-to-kinde/create-users-with-api.mdx | 171 ++++++++ .../switch-to-kinde/drip-feed-migration.mdx | 57 +++ .../switch-to-kinde/firebase-to-kinde.mdx | 82 ++-- .../migrate-users-bulk-import.mdx | 168 ++++++++ .../switch-to-kinde/supabase-to-kinde.mdx | 109 ++++++ ...witch-to-kinde-for-user-authentication.mdx | 192 +++------ .../existing-password-provided-workflow.mdx | 6 +- .../drip-feed-migration.mdx | 367 ++++++++++++++++++ 12 files changed, 1327 insertions(+), 345 deletions(-) create mode 100644 src/content/docs/get-started/switch-to-kinde/aws-cognito-to-kinde.mdx create mode 100644 src/content/docs/get-started/switch-to-kinde/azure-b2c-to-kinde.mdx create mode 100644 src/content/docs/get-started/switch-to-kinde/create-users-with-api.mdx create mode 100644 src/content/docs/get-started/switch-to-kinde/drip-feed-migration.mdx create mode 100644 src/content/docs/get-started/switch-to-kinde/migrate-users-bulk-import.mdx create mode 100644 src/content/docs/get-started/switch-to-kinde/supabase-to-kinde.mdx create mode 100644 src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx 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 a413cf489..e56ff4bf4 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 @@ -4,10 +4,14 @@ 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 @@ -30,152 +34,149 @@ keywords: - organizations - roles - permissions -updated: 2024-01-15 +updated: 2026-05-04 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: How to export users and passwords from Auth0 and migrate to Kinde, including guidance on social identities, migration window handling, drip-feed options, and Auth0-specific object mapping. --- -This guide is designed to help you migrate from Auth0 to Kinde. +This guide covers the Auth0-specific steps for exporting your users and migrating to Kinde. For import instructions and handling the migration window, see the [migration method guides](/get-started/switch-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. - -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 +## Key considerations -If you haven’t already got a Kinde account, [register for free here](https://app.kinde.com/register) (no credit card required). +- **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. -- 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. +## Export user data from Auth0 -## Step 2: Get the Auth0 extension to export users +### 1. Install the Auth0 export extension -Auth0 doesn’t have an export option by default, so you’ll need to install an export extension. +Auth0 doesn't have an export option by default, so you'll need to install an extension. -1. Go to [Auth0 Dashboard > Extensions](https://manage.auth0.com/#/extensions), and select **User Import / Export**. -2. When prompted, select **Install**. +1. Go to [Auth0 Dashboard > Extensions](https://manage.auth0.com/#/extensions) and select **User Import / Export**. +2. Select **Install**. ![Auth0 extension screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/2a8f1e39-2050-4c14-146a-338ecb57bb00/public) -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. +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. -## Step 3: Export user data from Auth0 +### 2. Export user data from Auth0 -File format guidelines: - -- 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. - -### 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 a JSON file to import into Kinde. -### Can’t get the passwords from Auth0? +## Step 4: Import into Kinde -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. +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Auth0**. -### Export Auth0 data + ![Import from Kinde tool screen shot](to be added) -1. Launch the extension by selecting **Import / Export Extension.** -2. Export your existing Auth0 users associated with database connections, select **Export**. +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. - ![Auth0 export selections screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/0748f464-d46f-4455-20dc-8f1c677fbb00/public) +For full import details, see [Bulk import users](/get-started/switch-to-kinde/migrate-users-bulk-import/). -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. +## Choose your migration method -## Step 4: Import user data into Kinde +### Bulk import (hard switch) -1. In Kinde, go to **Users**, then select **Import users**. -2. Select **Auth0.** +Export users and passwords from Auth0, import into Kinde, then switch. To handle new registrations or password changes during the migration window: - ![Import from Kinde tool screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/10090edb-3f26-405d-898d-2dfedd155100/public) +- 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/#step-4-force-a-password-reset-optional) for users whose password changed during the window. -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. +### Drip-feed via Kinde Workflow (recommended) -Once the password hashes have been imported, your users will be able to sign in to Kinde with their existing password. +Use the `user:existing_password_provided` workflow trigger to validate credentials against Auth0 automatically on first login. No bulk export needed, no downtime. -### How Auth0 user identities are treated on import +The workflow calls Auth0's Resource Owner Password Flow (`POST /oauth/token`) to verify the password before creating the user in Kinde. -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. +[Set up drip-feed migration →](/get-started/switch-to-kinde/drip-feed-migration/) -## After the migration +### App-hosted manual flow -### **Communication to users after import** +If your app hosts its own login form (email + password), you can push users to Kinde directly without a Kinde workflow: -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. +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: -Similarly, if you add users via API, Kinde does not send an email or notification to the user. + ```json + 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}" + } + ``` -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. +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. -### Additional consequences of migration +For the Kinde API steps, see [Create users with the API](/get-started/switch-to-kinde/create-users-with-api/). -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: +## Other objects you may want to bring from Auth0 -- 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. +- **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. -During and following the migration, we recommend checking for these issues. +Import objects via the [Kinde Management API](/kinde-apis/management/), or add them in the Kinde dashboard. -### There is no check for weak passwords +## More topics -When you import passwords, Kinde does not check for password strength. You’ll want to enforce your own password policies for users. +### Supported auth methods -### Other objects you may want to bring from Auth0 +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. -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/). +Auth methods are shown in the `connection` attribute of the `identities` array: -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: +- `Username-Password-Authentication` +- `email` +- `sms` +- `google-oauth2` +- `github` +- `twitch` +- `facebook` +- `bitbucket` +- `windowslive` -- 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). +### Can't get passwords from Auth0? -## Help is here +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](/get-started/switch-to-kinde/drip-feed-migration/) to avoid the export entirely. -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. +## Step 1: Prepare your Kinde business -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) +1. [Register for a Kinde account](https://app.kinde.com/register) if you haven't already. +2. Set up [authentication methods](/authenticate/authentication-methods/set-up-user-authentication/) to match your current Auth0 setup. +3. Enable [password authentication](/authenticate/authentication-methods/password-authentication/) if your users sign in with passwords. +4. [Create organizations](/build/organizations/add-and-manage-organizations/) if you use multi-tenancy. +5. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) if you plan to import these with users. -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..8d5cfd346 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/aws-cognito-to-kinde.mdx @@ -0,0 +1,101 @@ +--- +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-04 +featured: false +deprecated: false +ai_summary: How to export users from AWS Cognito and migrate to Kinde. Cognito does not allow password export, so drip-feed migration using the user:existing_password_provided workflow is the recommended approach for migrating users without forced password resets. +--- + +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. + +## Key considerations + +- **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. +- **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. +- **Enable `ADMIN_USER_PASSWORD_AUTH`** — if using drip-feed, ensure this auth flow is enabled on your Cognito App Client before starting the migration. +- **Track migrated users** — maintain a record of which users have been migrated in your own database to avoid re-checking Cognito on every login. + +## Step 1: Export users from Cognito + +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. + +Convert the JSON output to a Kinde-compatible CSV with these columns: + +```text +id,email,first_name,last_name,email_verified +{sub},{email},{given_name},{family_name},TRUE +``` + +The `id` field should be the Cognito `sub` (the user's UUID in Cognito). + +## Choose your migration method + +### Drip-feed (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**. + +[Set up drip-feed migration →](/get-started/switch-to-kinde/drip-feed-migration/) + +The [full 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). +3. Enable passwordless sign-in or password authentication in Kinde. +4. Follow the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/). + +## 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. 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..bd937a762 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/azure-b2c-to-kinde.mdx @@ -0,0 +1,133 @@ +--- +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-04 +featured: false +deprecated: false +ai_summary: How to export users from Azure B2C and migrate to Kinde, covering four migration methods including bulk import, API-based sync, drip-feed via ROPC, and hard cutover during a maintenance window. +--- + +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. + +## 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. +- **Drip-feed uses the ROPC endpoint** — the Azure B2C Resource Owner Password Credentials (ROPC) token endpoint allows the workflow to validate credentials on first login. +- **Enable Enumeration protection** — before enabling drip-feed, go to **Settings > Attack protection > Enumeration protection** in Kinde and turn it on. +- **Block registrations, not logins, during a maintenance window** — if using a hard cutover, blocking only new registrations (not logins) is sufficient since passwords are not being migrated. +- **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. + +## Step 1: 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,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. + +[Set up drip-feed migration →](/get-started/switch-to-kinde/drip-feed-migration/) + +The [full 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. 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 index d01f6135e..5e37da7af 100644 --- 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 @@ -8,22 +8,20 @@ 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: Step-by-step guide to migrating users and hashed passwords from Clerk to Kinde, including how to export user data and import it into Kinde. +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 -app_context: - - m: users - - s: list sdk: [] languages: - csv audience: - developers - admins -complexity: advanced +complexity: intermediate keywords: - clerk migration - clerk to kinde @@ -34,15 +32,19 @@ keywords: - csv import - authentication migration - clerk export -updated: 2026-04-28 +updated: 2026-05-04 featured: false deprecated: false -ai_summary: "This guide walks through migrating users from Clerk to Kinde in five steps. Because Clerk supports exporting hashed passwords, migrated users can sign in with their existing passwords without a forced reset. First, export users from the Clerk dashboard as a CSV. Second, prepare the CSV by mapping columns to Kinde's format — the only required field is `email`, but you can also include `hashed_password` and `hashing_method` (bcrypt, sha256, md5, crypt, or wordpress), plus recommended fields like `first_name`, `last_name`, `email_verified`, `id`, `phone`, `external_organization_id`, `role_key`, and `permission_key`. Third, set up your Kinde business by enabling authentication methods, creating organizations, and defining roles and permissions before importing. Fourth, import the CSV via Users > Import users > Custom CSV. Fifth, test the migration by signing in with a migrated user. Review the CSV for errors before importing — Kinde reports issues and skips already-imported records on re-import. After migration, notify users of any changes to their sign-in experience." +ai_summary: How to export users and hashed passwords from Clerk and import them into Kinde. Clerk exports bcrypt-hashed passwords which Kinde supports natively, so users can sign in without resetting their password. --- -Migrate your users from Clerk to Kinde. The process involves exporting user data from the Clerk dashboard, preparing the CSV, and importing it into Kinde. +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. -Clerk supports exporting hashed passwords out of the box, so your migrated users can sign in with their existing passwords without having to reset them. +## 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 @@ -51,84 +53,63 @@ Clerk supports exporting hashed passwords out of the box, so your migrated users 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 the **User exports** section, select **Export users**. -5. When the export is ready, select **Download**. It will download a CSV file. +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. Prepare your user CSV +### 2. Map Clerk columns to Kinde's CSV format -Modify your Clerk CSV columns to match the supported columns by Kinde: +Modify your Clerk CSV to use the column names Kinde expects. The only required column is `email` — everything else is optional but recommended. -**Required columns:** +**Required:** | Column | Notes | |--------|-------| | `email` | Minimum required field | -**Password columns (if importing hashed passwords):** +**Password columns (recommended — preserves existing passwords):** | Column | Notes | |--------|-------| -| `hashed_password` | The user's password hashed with a hashing algorithm | -| `hashing_method` | Kinde supports `bcrypt`, `sha256`, `md5`, `crypt`, `wordpress` | +| `hashed_password` | The user's bcrypt-hashed password from Clerk | +| `hashing_method` | Set this to `bcrypt` for all Clerk exports | -**Recommended columns:** +**Recommended:** | Column | Notes | |--------|-------| | `first_name`, `last_name` | User's name | | `email_verified` | `TRUE` or `FALSE` | -| `id` | Clerk user ID — helps match records during import | +| `id` | Clerk user ID — helps match records on re-import | | `phone` | International format, e.g. `+61555111555` | -| `external_organization_id` | Organization ID to import the user into (if applicable) | -| `role_key` | Role key(s) to assign; comma-separate multiple values | -| `permission_key` | Permission key(s) to assign; comma-separate multiple values | - - - -### 3. Prepare your Kinde business +| `external_organization_id` | Organization ID (if applicable). 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 | -Configure your Kinde business to match or improve on your current Clerk setup. + -### 4. Import users into Kinde +### 3. Import into Kinde 1. In Kinde, go to **Users**, then select **Import users**. -2. Select **Custom CSV**, then select **Next**. -3. Select the CSV file you prepared and select **Import**. - - After the import, you will find the list of users in the **Users** tab. - - For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). +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. -### 5. Test the migration - -1. Run your Kinde application. -2. Sign in with a test user you migrated. -3. Verify you can sign in with the test user. +See the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to learn more. ## Troubleshooting -**Check for errors before importing:** - -Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes will be skipped. +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. ## Next steps -- Notify your users of the change before going live, especially if they’ll experience a different sign-in flow. -- Verify users are able to sign in to Kinde with their existing Clerk login methods. +- Verify users can sign in to Kinde with their existing Clerk credentials. +- Notify users of any changes to their sign-in experience before going live. +- [Get support](/get-started/get-support/) if you need help with your migration. \ 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..43cee6f3e --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/create-users-with-api.mdx @@ -0,0 +1,171 @@ +--- +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 prefered 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", + "salt": "", + "salt_position": "", + "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 index e7fd84958..af2b26499 100644 --- 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 @@ -2,15 +2,16 @@ page_id: f2a8d3e6-7c14-4b09-a5e1-3d8c7f29b045 title: Migrate to Kinde from Firebase Authentication sidebar: - order: 4 + 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: Step-by-step guide to migrating users from Firebase Authentication to Kinde, including export options, SCRYPT password limitations, and alternative sign-in strategies. +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 @@ -21,7 +22,7 @@ languages: audience: - developers - admins -complexity: advanced +complexity: intermediate keywords: - firebase migration - firebase authentication @@ -32,19 +33,21 @@ keywords: - password migration - csv import - authentication migration -updated: 2026-04-28 +updated: 2026-05-04 featured: false deprecated: false -ai_summary: "This guide covers migrating users from Firebase Authentication to Kinde in five steps. The critical limitation to know upfront: Firebase uses SCRYPT password hashing, which Kinde does not currently support for import — users will need to reset their password or sign in via a new method on first login. First, export users from Firebase using the CLI command `firebase auth:export users.json --format=json`, which exports emails, display names, UIDs, and hashed passwords. Second, convert the export to a Kinde-compatible CSV — the only required field is `email`, with recommended fields including `first_name`, `last_name`, `email_verified`, and `id` (Firebase UID). Third, set up your Kinde business by enabling authentication methods suited for your users — passwordless is recommended given the password limitation. Fourth, import the CSV via Users > Import users > Custom CSV. Fifth, test by signing in with a migrated user. Before going live, notify users they will need to use a new sign-in method since Firebase passwords cannot be carried over." +ai_summary: How to export users from Firebase Authentication and import them into Kinde. Firebase uses the SCRYPT hashing algorithm which Kinde does not currently support for import, so users will need to sign in via a new method or reset their password. --- -Migrate your users from Firebase Authentication to Kinde. The process involves exporting user data from Firebase, preparing the CSV, and importing it into Kinde. +Migrate your users from Firebase Authentication to Kinde. The process involves exporting user data from Firebase and importing into Kinde. -The key limitation to know upfront: Firebase uses the `SCRYPT` hashing algorithm for passwords, which Kinde does not currently support for import. If you're switching to passwordless or social sign-on, this isn't a problem — import users without passwords and they'll use the new auth method on first sign-in. If password continuity is critical, [submit a feature request](https://updates.kinde.com/) to prioritize SCRYPT support. +## Key considerations -## Migration guide +- **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. -### 1. Export users from Firebase +## Step 1: Export users from Firebase Make sure you have the [Firebase CLI](https://firebase.google.com/docs/cli) installed, then run: @@ -54,70 +57,47 @@ 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. Prepare your user CSV +## Step 2: Prepare your CSV -Convert your Firebase JSON export into a CSV using the format below. Remove the password related columns from the CSV, so your users will be prompted to set a new password on first sign-in. +Convert your Firebase JSON export into a CSV. Omit the password columns — users will be prompted to set a new password or use another sign-in method on first login. -**Required columns:** +**Required:** | Column | Notes | |--------|-------| | `email` | Minimum required field | -**Recommended columns:** +**Recommended:** | Column | Notes | |--------|-------| -| `first_name`, `last_name` | User's name | +| `first_name`, `last_name` | User's name (from `displayName` in Firebase) | | `email_verified` | `TRUE` or `FALSE` | -| `id` | Firebase UID — helps match records during import | +| `id` | Firebase UID — helps match records during re-imports | | `phone` | International format, e.g. `+61555111555` | -| `external_organization_id` | Organization ID to import the user into (if applicable) | -| `role_key` | Role key(s) to assign; comma-separate multiple values | -| `permission_key` | Permission key(s) to assign; comma-separate multiple values | +| `external_organization_id` | Organization ID (if applicable). 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 | -### 3. Prepare your Kinde business +## Step 3: Import into Kinde -Configure your Kinde business to match or improve on your current Firebase setup. +Follow the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to prepare your Kinde business and import the CSV. -1. Register for a Kinde account and [finish the onboarding process](/get-started/guides/first-things-first/) if you haven't already. -2. Set up [authentication methods](/authenticate/authentication-methods/set-up-user-authentication/) to match your current Firebase setup. Since Firebase passwords cannot be imported, we recommend enabling at least one passwordless option: - - **Passwordless** — one-time code via email or SMS (recommended) - - **Social sign-on** — Google, Apple, GitHub, Microsoft, and more - - **Password** — enable if you plan to have users set a new password on first sign-in - - **Enterprise** — SAML or Microsoft Entra ID -3. [Create organizations](/build/organizations/add-and-manage-organizations/) in Kinde if you use multi-tenancy (e.g. a B2B app). -4. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) in Kinde if you plan to import these alongside users. +When setting up authentication in Kinde, enable at least one of these given that passwords cannot be migrated: -### 4. Import users into Kinde +- **Passwordless** — one-time code via email or SMS (recommended) +- **Social sign-on** — Google, Apple, GitHub, Microsoft, and more +- **Password** — enable if you want users to set a new password on first sign-in -1. In Kinde, go to **Users**, then select **Import users**. -2. Select **Custom CSV**, then select **Next**. -3. Select the CSV file you prepared and select **Import**. - - After the import, you will find the list of users in the **Users** tab. - - For full instructions, see [Import or update users in bulk](/manage-users/add-and-edit/import-users-in-bulk/). - -### 5. Test the migration - -1. Run your Kinde application. -2. Sign in with a test user you migrated. -3. Verify you can sign in using passwordless, social, or password reset — whichever method you configured. - -## Troubleshooting - -**Check for errors before importing:** - -Review the CSV for missing or duplicated values. Kinde will flag errors during import and report them back. Most errors can be fixed by editing the CSV and re-importing — records already imported without changes will be skipped. +When prompted to select an import type in Kinde, select **Custom CSV**. ## Next steps -- Notify your users of the change before going live — since Firebase passwords cannot be migrated, they'll need to sign in using a new method. -- Verify users are able to sign in to Kinde using the authentication methods you configured. +- Notify users before going live — since Firebase passwords cannot be migrated, they will need to sign in using a new method. +- Verify users can sign in using the authentication methods you configured. 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..17c89df14 --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/migrate-users-bulk-import.mdx @@ -0,0 +1,168 @@ +--- +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 +updated: 2026-05-04 +featured: false +deprecated: false +ai_summary: How to prepare a CSV file and bulk import users into Kinde, including hashed passwords, roles, organizations, and handling edge cases during the migration window. +--- + +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. + +## Step 1: Prepare your Kinde business + +Before importing: + +1. Enable [password authentication](/authenticate/authentication-methods/password-authentication/) if you're migrating password hashes. +2. [Create organizations](/build/organizations/add-and-manage-organizations/) if you use multi-tenancy and want to import users into specific orgs. +3. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) if you plan to import these alongside users. + +## Step 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/) +- [Firebase Authentication](/get-started/switch-to-kinde/firebase-to-kinde/) +- [Supabase](/get-started/switch-to-kinde/supabase-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're migrating from your own system, prepare the data as described below. + +## Step 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 | Notes | +|--------|-------| +| `email` | Minimum required field | + +### Recommended + +| 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 | — | + + + + + +### Example CSV + +```text +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 +``` + +### 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. + +## Step 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 +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/). + +### Communication to 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. 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..611de633d --- /dev/null +++ b/src/content/docs/get-started/switch-to-kinde/supabase-to-kinde.mdx @@ -0,0 +1,109 @@ +--- +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 + - user import + - password migration + - bcrypt + - csv import +updated: 2026-05-04 +featured: false +deprecated: false +ai_summary: How to export users and hashed passwords from Supabase Auth using a SQL query and import them into Kinde. Supabase uses bcrypt which Kinde supports natively, so users can sign in without resetting their password. +--- + +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. + +## 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. + +## Step 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, + 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**. + + + +## Step 2: Prepare the CSV for Kinde + +Rename the exported columns to match Kinde's expected format: + +| Supabase column | Kinde column | +|----------------|--------------| +| `id` | `id` | +| `email` | `email` | +| `encrypted_password` | `hashed_password` | +| `email_verified` | `email_verified` | +| `first_name` | `first_name` | +| `last_name` | `last_name` | + +Add a `hashing_method` column and set every row to `bcrypt`. + +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 +``` + +## Step 3: Import into Kinde + +Follow the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to prepare your Kinde business and import the CSV. + +When prompted to select an import type in Kinde, select **Custom CSV**. + +## Next steps + +- Verify users can sign in to Kinde with their existing Supabase credentials. +- For users who signed in via social providers (Google, GitHub, etc.), notify them they may need to re-link their social login after the migration. 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..062158dd6 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,96 @@ 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 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 to kinde + - switch auth provider + - bulk import + - drip feed migration + - api migration +updated: 2026-05-04 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: Overview of migration approaches for moving users from any auth system to Kinde, including bulk import, API-based creation, and drip-feed migration, with links to provider-specific export guides. --- -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. +Switching auth providers doesn't have to be painful. This guide helps you choose the right migration approach and points you to the right tools 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/set-up-user-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..90a89a0d1 --- /dev/null +++ b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx @@ -0,0 +1,367 @@ +--- +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 +sdk: kinde infrastructure +languages: + - TypeScript + - JavaScript +audience: + - developers +complexity: advanced +keywords: + - drip feed migration + - progressive migration + - password migration workflow + - existing password workflow + - zero downtime migration + - auth migration +updated: 2026-05-04 +featured: false +deprecated: false +ai_summary: Tutorial for implementing drip-feed user migration using the user:existing_password_provided workflow trigger in Kinde, with provider-specific examples for Auth0, AWS Cognito, and Azure B2C. +--- + +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](https://kinde.com/) account (sign up for free) +- A [GitHub](https://github.com/) account +- The [workflow base template](https://github.com/kinde-starter-kits/workflow-base-template) repo +- Your legacy auth system's password validation API (examples for Auth0, Cognito, and Azure B2C are provided below) + +## Before you start + +### Bulk import emails first + +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. This seeds Kinde with your user list so the trigger can fire on first login. + +### Enable Enumeration protection + +Go to **Settings > Attack protection > Enumeration protection** and turn it on. This is required for the workflow to function correctly. + +## Step 1: Create the workflow code + +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. + +### Generic workflow + +Use this 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": {}, + }, +}; + +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, + }); +} +``` + +### Auth0 variant + +Validates credentials using Auth0's Resource Owner Password Flow. + +```typescript +import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, +} from "@kinde/infrastructure"; + +export const workflowSettings: WorkflowSettings = { + id: "dripFeedMigrationAuth0", + name: "Drip-feed migration (Auth0)", + trigger: WorkflowTrigger.ExistingPasswordProvided, + failurePolicy: { action: "stop" }, + bindings: { + "kinde.fetch": {}, + "kinde.secureFetch": {}, + "kinde.env": {}, + }, +}; + +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 auth0Response = await kinde.secureFetch( + `https://${kinde.env.get("AUTH0_DOMAIN")}/oauth/token`, + { + method: "POST", + responseFormat: "json", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + grant_type: "password", + username: providedEmail, + password, + audience: kinde.env.get("AUTH0_AUDIENCE"), + client_id: kinde.env.get("AUTH0_CLIENT_ID"), + client_secret: kinde.env.get("AUTH0_CLIENT_SECRET"), + }), + } + ); + + 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, + }); +} +``` + +Set the following [environment variables](/workflows/configuration/environment-variables-and-secrets/) in Kinde: `AUTH0_DOMAIN`, `AUTH0_AUDIENCE`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`. + +### AWS Cognito variant + +Uses Cognito's `ADMIN_USER_PASSWORD_AUTH` flow. Ensure this flow is enabled on your Cognito App Client before deploying. + +```typescript +import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, +} from "@kinde/infrastructure"; + +export const workflowSettings: WorkflowSettings = { + id: "dripFeedMigrationCognito", + name: "Drip-feed migration (Cognito)", + trigger: WorkflowTrigger.ExistingPasswordProvided, + failurePolicy: { action: "stop" }, + bindings: { + "kinde.fetch": {}, + "kinde.secureFetch": {}, + "kinde.env": {}, + }, +}; + +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 cognitoResponse = await kinde.secureFetch( + `https://cognito-idp.${kinde.env.get("AWS_REGION")}.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: kinde.env.get("COGNITO_CLIENT_ID"), + UserPoolId: kinde.env.get("COGNITO_USER_POOL_ID"), + 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, + }); +} +``` + +Set the following environment variables: `AWS_REGION`, `COGNITO_CLIENT_ID`, `COGNITO_USER_POOL_ID`. You will also need to sign the request with AWS Signature V4 — add your signing logic or use a Lambda proxy that handles auth. + +### Azure B2C variant + +Uses the Azure B2C Resource Owner Password Credentials (ROPC) token endpoint. + +```typescript +import { + onExistingPasswordProvidedEvent, + WorkflowSettings, + WorkflowTrigger, + createKindeAPI, +} 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.secureFetch": {}, + "kinde.env": {}, + }, +}; + +export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; + + if (hasUserRecordInKinde) return; + + const tenant = kinde.env.get("AZURE_B2C_TENANT"); + const policy = kinde.env.get("AZURE_B2C_ROPC_POLICY"); + const clientId = kinde.env.get("AZURE_B2C_CLIENT_ID"); + const scope = kinde.env.get("AZURE_B2C_SCOPE"); + + const body = new URLSearchParams({ + grant_type: "password", + client_id: clientId, + scope: `openid ${scope}`, + username: providedEmail, + password, + response_type: "token", + }); + + const azureResponse = await kinde.secureFetch( + `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, + }); +} +``` + +Set the following environment variables: `AZURE_B2C_TENANT`, `AZURE_B2C_ROPC_POLICY`, `AZURE_B2C_CLIENT_ID`, `AZURE_B2C_SCOPE`. + +5. Push your workflow code to GitHub: + + ```bash + git add . + git commit -m "add drip-feed migration workflow" + git push + ``` + +## Step 2: 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/). + +## Step 3: Test the migration + +1. Sign in to your Kinde dashboard and go to **Authentication**. +2. Enable **Email + password** if it isn't already enabled, and select **Save**. +3. Sign in as a test user (one who exists in your legacy system but not yet fully in Kinde). +4. Confirm the user appears in **Users** in Kinde after signing in. +5. Sign in as the same user a second time — they should authenticate directly through Kinde this time. + +## 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. From d039f74d985433114235f867889515ca06fc945b Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Tue, 5 May 2026 19:13:56 +0600 Subject: [PATCH 06/14] update clerk, auth0, and main page --- .../switch-to-kinde/auth0-to-kinde.mdx | 95 +++++++++++-------- .../switch-to-kinde/clerk-to-kinde.mdx | 62 ++++++------ ...witch-to-kinde-for-user-authentication.mdx | 27 ++++-- 3 files changed, 103 insertions(+), 81 deletions(-) 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 e56ff4bf4..be9549b16 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 @@ -15,6 +15,8 @@ description: Export users and passwords from Auth0 and migrate to Kinde, with gu topics: - get-started - switch-to-kinde + - user-management + - authentication sdk: [] languages: - json @@ -26,26 +28,43 @@ 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: 2026-05-04 +updated: 2026-05-05 featured: false deprecated: false -ai_summary: How to export users and passwords from Auth0 and migrate to Kinde, including guidance on social identities, migration window handling, drip-feed options, and Auth0-specific object mapping. +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 covers the Auth0-specific steps for exporting your users and migrating to Kinde. For import instructions and handling the migration window, see the [migration method guides](/get-started/switch-to-kinde/). +This guide covers the Auth0-specific steps for exporting your users and migrating 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. +### 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) +- Auth0 account with extension installation permissions + ## Key considerations - **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. @@ -81,35 +100,15 @@ The extension appears in your list of installed extensions. The first time you l You will have a JSON file to import into Kinde. -## Step 4: Import into Kinde - -1. In Kinde, go to **Users**, then select **Import users**. -2. Select **Auth0**. - - ![Import from Kinde tool screen shot](to be added) - -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. - -For full import details, see [Bulk import users](/get-started/switch-to-kinde/migrate-users-bulk-import/). - ## Choose your migration method -### Bulk import (hard switch) - -Export users and passwords from Auth0, import into Kinde, then switch. To handle new registrations or password changes during the migration window: - -- 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/#step-4-force-a-password-reset-optional) for users whose password changed during the window. - ### Drip-feed via Kinde Workflow (recommended) Use the `user:existing_password_provided` workflow trigger to validate credentials against Auth0 automatically on first login. No bulk export needed, no downtime. The workflow calls Auth0's Resource Owner Password Flow (`POST /oauth/token`) to verify the password before creating the user in Kinde. -[Set up drip-feed migration →](/get-started/switch-to-kinde/drip-feed-migration/) +[Set up drip-feed migration →](/workflows/workflow-tutorials/drip-feed-migration/) ### App-hosted manual flow @@ -135,17 +134,25 @@ If your app hosts its own login form (email + password), you can push users to K For the Kinde API steps, see [Create users with the API](/get-started/switch-to-kinde/create-users-with-api/). -## Other objects you may want to bring from Auth0 +### Bulk import (hard switch) -- **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. +Export users and passwords from Auth0, import into Kinde, then switch. Follow the steps below: -Import objects via the [Kinde Management API](/kinde-apis/management/), or add them in the Kinde dashboard. +1. In Kinde, go to **Users**, then select **Import users**. +2. Select **Auth0**. + + ![Import from Kinde tool screen shot](https://imagedelivery.net/skPPZTHzSlcslvHjesZQcQ/06ceef1a-0236-4f42-6598-c60dd511a400/socialsharingimage) + +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. + +For full import details, see [Bulk import users](/get-started/switch-to-kinde/migrate-users-bulk-import/). + +To handle new registrations or password changes during the migration window: + +- 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. ## More topics @@ -165,17 +172,21 @@ Auth methods are shown in the `connection` attribute of the `identities` array: - `bitbucket` - `windowslive` -### Can't get passwords from Auth0? +### Other objects you may want to bring from Auth0 -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](/get-started/switch-to-kinde/drip-feed-migration/) to avoid the export entirely. +- **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. + +Import objects via the [Kinde Management API](/kinde-apis/management/), or add them in the Kinde dashboard. -## Step 1: Prepare your Kinde business +### Can't get passwords from Auth0? -1. [Register for a Kinde account](https://app.kinde.com/register) if you haven't already. -2. Set up [authentication methods](/authenticate/authentication-methods/set-up-user-authentication/) to match your current Auth0 setup. -3. Enable [password authentication](/authenticate/authentication-methods/password-authentication/) if your users sign in with passwords. -4. [Create organizations](/build/organizations/add-and-manage-organizations/) if you use multi-tenancy. -5. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) if you plan to import these with users. +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](/get-started/switch-to-kinde/drip-feed-migration/) to avoid the export entirely. ## Get support 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 index 5e37da7af..fdf5fc940 100644 --- 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 @@ -29,17 +29,27 @@ keywords: - user import - password migration - hashed passwords + - bcrypt - csv import + - csv column mapping + - bulk import - authentication migration - clerk export -updated: 2026-05-04 + - clerk csv +updated: 2026-05-05 featured: false deprecated: false -ai_summary: How to export users and hashed passwords from Clerk and import them into Kinde. Clerk exports bcrypt-hashed passwords which Kinde supports natively, so users can sign in without resetting their password. +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. @@ -62,32 +72,20 @@ See Clerk's documentation on [exporting users](https://clerk.com/docs/guides/dev ### 2. Map Clerk columns to Kinde's CSV format -Modify your Clerk CSV to use the column names Kinde expects. The only required column is `email` — everything else is optional but recommended. - -**Required:** - -| Column | Notes | -|--------|-------| -| `email` | Minimum required field | +Rename the columns in your Clerk export to match what Kinde expects. The only required column is `email` — everything else is optional but recommended. -**Password columns (recommended — preserves existing passwords):** +| 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` | -| Column | Notes | -|--------|-------| -| `hashed_password` | The user's bcrypt-hashed password from Clerk | -| `hashing_method` | Set this to `bcrypt` for all Clerk exports | - -**Recommended:** - -| Column | Notes | -|--------|-------| -| `first_name`, `last_name` | User's name | -| `email_verified` | `TRUE` or `FALSE` | -| `id` | Clerk user ID — helps match records on re-import | -| `phone` | International format, e.g. `+61555111555` | -| `external_organization_id` | Organization ID (if applicable). 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 | +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/#step-3-prepare-your-csv) in the bulk import guide. -## Step 2: Prepare the CSV for Kinde +### 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` | -Rename the exported columns to match Kinde's expected format: +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/#step-3-prepare-your-csv) in the bulk import guide. -| Supabase column | Kinde column | -|----------------|--------------| -| `id` | `id` | -| `email` | `email` | -| `encrypted_password` | `hashed_password` | -| `email_verified` | `email_verified` | -| `first_name` | `first_name` | -| `last_name` | `last_name` | + Your final CSV should look like this: @@ -97,13 +118,21 @@ abc-123,bills@company.com,Bill,Smith,TRUE,$2a$10$examplehash,bcrypt def-456,carlosg@company.com,Carlos,Garcia,TRUE,$2a$10$examplehash,bcrypt ``` -## Step 3: Import into Kinde +### 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. -Follow the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-import/) to prepare your Kinde business and import the CSV. +### 4. Test the migration -When prompted to select an import type in Kinde, select **Custom CSV**. +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. -## Next steps +## Get support -- Verify users can sign in to Kinde with their existing Supabase credentials. -- For users who signed in via social providers (Google, GitHub, etc.), notify them they may need to re-link their social login after the migration. +If you need help with your migration, contact [Kinde support.](https://kinde.com/support) From 47c784bbf5004b7f282a944b96bb9d8e72eba32c Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Thu, 7 May 2026 12:56:58 +0600 Subject: [PATCH 08/14] update the bulk import guide --- .../migrate-users-bulk-import.mdx | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) 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 index 17c89df14..0f5592140 100644 --- 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 @@ -29,48 +29,60 @@ keywords: - password migration - hashed passwords - import users -updated: 2026-05-04 + - migrate users + - bulk user migration + - password hash migration + - NDJSON import +updated: 2026-05-07 featured: false deprecated: false -ai_summary: How to prepare a CSV file and bulk import users into Kinde, including hashed passwords, roles, organizations, and handling edge cases during the migration window. +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. -## Step 1: Prepare your Kinde business +## Example CSV -Before importing: +```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 -1. Enable [password authentication](/authenticate/authentication-methods/password-authentication/) if you're migrating password hashes. -2. [Create organizations](/build/organizations/add-and-manage-organizations/) if you use multi-tenancy and want to import users into specific orgs. -3. Add [roles](/manage-users/roles-and-permissions/user-roles/) and [permissions](/manage-users/roles-and-permissions/user-permissions/) if you plan to import these alongside users. +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). -## Step 2: Export users from your provider +### 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/) -- [Firebase Authentication](/get-started/switch-to-kinde/firebase-to-kinde/) -- [Supabase](/get-started/switch-to-kinde/supabase-to-kinde/) -- [AWS Cognito](/get-started/switch-to-kinde/aws-cognito-to-kinde/) -- [Azure B2C](/get-started/switch-to-kinde/azure-b2c-to-kinde/) +- [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're migrating from your own system, prepare the data as described below. +If you are migrating from your own system, prepare the data to match the format described below. -## Step 3: Prepare your CSV +### 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 +**Required column:** | Column | Notes | |--------|-------| | `email` | Minimum required field | -### Recommended +**Recommended columns:** | Column | Notes | |--------|-------| @@ -88,7 +100,7 @@ Kinde imports users from a CSV file (up to 5MB; Auth0 imports accept NDJSON up t -### Password columns +**Password columns:** Include these if you're migrating hashed passwords: @@ -122,25 +134,19 @@ Provide the hash in hex format. For `salt_format`, specify `hex` for a hex-encod -### Example CSV - -```text -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 -``` - -### Check for errors before importing +**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. -## Step 4: Import users into Kinde +### 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. @@ -156,7 +162,7 @@ If users can still register or change their password while you migrate, you'll m - **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/). -### Communication to users +### 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). @@ -166,3 +172,7 @@ Kinde does not notify users when they are imported. Plan your own communication, - 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 From 13a3eeca76dbfe2c71b2639df05141106f853e5d Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Thu, 7 May 2026 13:40:48 +0600 Subject: [PATCH 09/14] drip update --- .../drip-feed-migration.mdx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx index 90a89a0d1..452a2ed31 100644 --- a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx +++ b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx @@ -32,7 +32,7 @@ keywords: updated: 2026-05-04 featured: false deprecated: false -ai_summary: Tutorial for implementing drip-feed user migration using the user:existing_password_provided workflow trigger in Kinde, with provider-specific examples for Auth0, AWS Cognito, and Azure B2C. +ai_summary: --- 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. @@ -41,22 +41,25 @@ Each user is migrated the first time they sign in: Kinde validates their passwor ### What you need -- A [Kinde](https://kinde.com/) account (sign up for free) -- A [GitHub](https://github.com/) account -- The [workflow base template](https://github.com/kinde-starter-kits/workflow-base-template) repo +- 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) ## Before you start -### Bulk import emails first +### 1. Bulk import emails first 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. This seeds Kinde with your user list so the trigger can fire on first login. -### Enable Enumeration protection +### 2.Enable Enumeration protection -Go to **Settings > Attack protection > Enumeration protection** and turn it on. This is required for the workflow to function correctly. +Go to your Kinde dashboard > **Settings > Attack protection > Enumeration protection** and turn it on. This is required for the workflow to function correctly. -## Step 1: Create the workflow code + + +## Workflow setup + +### 1. Create the workflow code 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**. From 76b273dbd4b62f7b7eef50c93b3168a1ac45b282 Mon Sep 17 00:00:00 2001 From: Tamal Chowdhury Date: Thu, 7 May 2026 20:33:34 +0600 Subject: [PATCH 10/14] update the drip feed doc --- ...witch-to-kinde-for-user-authentication.mdx | 2 +- .../drip-feed-migration.mdx | 46 +++++++++++++++++-- 2 files changed, 42 insertions(+), 6 deletions(-) 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 c956e3c32..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 @@ -85,7 +85,7 @@ Users migrate automatically as they log in. A Kinde workflow validates each logi **Best for:** Teams that want zero downtime and a seamless user experience. Recommended for most teams. -[Drip-feed migration →](/get-started/switch-to-kinde/drip-feed-migration/) +[Drip-feed migration tutorial →](/workflows/workflow-tutorials/drip-feed-migration/) ### Hard cutover (maintenance window) diff --git a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx index 452a2ed31..6f22635a7 100644 --- a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx +++ b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx @@ -32,7 +32,7 @@ keywords: updated: 2026-05-04 featured: false deprecated: false -ai_summary: +ai_summary: "hello" --- 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. @@ -45,17 +45,40 @@ Each user is migrated the first time they sign in: Kinde validates their passwor - 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) -## Before you start +## Kinde configuration -### 1. Bulk import emails first +### 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. This seeds Kinde with your user list so the trigger can fire on first login. +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. Make sure the imported emails are set to `email_verified` to `TRUE` so it can properly fire on first login. This seeds Kinde with your user list so the trigger can fire on first login. Here is an example CSV format of your exported users: -### 2.Enable Enumeration protection +```text +# users.csv +email,email_verified +user1@example.com,TRUE +user2@example.com,TRUE +user3@example.com,TRUE +``` + +### 2. Enable Enumeration protection Go to your Kinde dashboard > **Settings > Attack protection > Enumeration protection** and turn it on. This is required for the workflow to function correctly. +### 3. Setup a Kinde Management API + +This workflow will update the user password in Kinde, so you need to setup a Kinde Management API to do this. +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 ## Workflow setup @@ -79,6 +102,19 @@ Go to your Kinde dashboard > **Settings > Attack protection > Enumeration protec 4. Add the workflow code below. Choose the version for your legacy provider, or adapt the generic version for your own system. +### 2. Setup kinde application + +Set up application in kinde and set password authentication. + +### 2. Deploy the workflow + +git setup here. + +Go to settings **Environment > Git repo** and select **Connect GitHub** and follow the prompts to connect your GitHub repository. +Select your workflow repo, choose the branch (defaults to main) and select **Next**. +You will find your workflow by going to your Kinde dashboard > **Workflows** and select the **Drip-feed migration** workflow. + + ### Generic workflow Use this as a starting point if your legacy system has a custom password validation endpoint. From e6536afa27c6b2ee8e5453e8e13811b2f14867cd Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Sun, 10 May 2026 20:53:26 +0600 Subject: [PATCH 11/14] update the drip feed doc --- .../drip-feed-migration.mdx | 88 +++++++++++-------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx index 6f22635a7..2adb25b29 100644 --- a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx +++ b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx @@ -45,18 +45,18 @@ Each user is migrated the first time they sign in: Kinde validates their passwor - 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) -## Kinde configuration +## 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. Make sure the imported emails are set to `email_verified` to `TRUE` so it can properly fire on first login. This seeds Kinde with your user list so the trigger can fire on first login. Here is an example CSV format of your exported users: +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,email_verified -user1@example.com,TRUE -user2@example.com,TRUE -user3@example.com,TRUE +email +user1@example.com +user2@example.com +user3@example.com ``` ### 2. Enable Enumeration protection @@ -80,9 +80,29 @@ This workflow will update the user password in Kinde, so you need to setup a Kin - `KINDE_WF_M2M_CLIENT_ID` - `KINDE_WF_M2M_CLIENT_SECRET` - Ensure this is setup with **Sensitive** flag enabled to prevent accidental sharing -## Workflow setup +### 4. Set up additional environment variables -### 1. Create the workflow code +You may need to add additional environment variables to your workflow, such as config details, API URLs, etc. Add them with the steps: + +1. Go to your Kinde dashboard > **Settings > Data management > Env variables** and set up your additional environment variables. + +If you need to store a sensitive value, ensure this is setup with **Sensitive** flag enabled to prevent accidental sharing. + +### 5. Set up an encryption key + +Encryption keys protect sensitive data such as passwords when making secure API calls. Create an encryption key for your workflow: + +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 more on how to [Decrypt workflow‑encrypted payloads](/workflows/manage-workflows/encrypt-decrypt-workflows/#decrypt-workflowencrypted-payloads) here. + +## 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**. @@ -102,20 +122,7 @@ This workflow will update the user password in Kinde, so you need to setup a Kin 4. Add the workflow code below. Choose the version for your legacy provider, or adapt the generic version for your own system. -### 2. Setup kinde application - -Set up application in kinde and set password authentication. - -### 2. Deploy the workflow - -git setup here. - -Go to settings **Environment > Git repo** and select **Connect GitHub** and follow the prompts to connect your GitHub repository. -Select your workflow repo, choose the branch (defaults to main) and select **Next**. -You will find your workflow by going to your Kinde dashboard > **Workflows** and select the **Drip-feed migration** workflow. - - -### Generic workflow +### 2A. Generic workflow (your custom backend) Use this as a starting point if your legacy system has a custom password validation endpoint. @@ -167,8 +174,9 @@ export default async function Workflow(event: onExistingPasswordProvidedEvent) { }); } ``` +Check out the provider specific variants below. -### Auth0 variant +### 2B. Auth0 variant Validates credentials using Auth0's Resource Owner Password Flow. @@ -187,7 +195,6 @@ export const workflowSettings: WorkflowSettings = { failurePolicy: { action: "stop" }, bindings: { "kinde.fetch": {}, - "kinde.secureFetch": {}, "kinde.env": {}, }, }; @@ -198,7 +205,7 @@ export default async function Workflow(event: onExistingPasswordProvidedEvent) { if (hasUserRecordInKinde) return; // Validate against Auth0 Resource Owner Password Flow - const auth0Response = await kinde.secureFetch( + const auth0Response = await kinde.fetch( `https://${kinde.env.get("AUTH0_DOMAIN")}/oauth/token`, { method: "POST", @@ -232,7 +239,7 @@ export default async function Workflow(event: onExistingPasswordProvidedEvent) { Set the following [environment variables](/workflows/configuration/environment-variables-and-secrets/) in Kinde: `AUTH0_DOMAIN`, `AUTH0_AUDIENCE`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`. -### AWS Cognito variant +### 2C. AWS Cognito variant Uses Cognito's `ADMIN_USER_PASSWORD_AUTH` flow. Ensure this flow is enabled on your Cognito App Client before deploying. @@ -251,7 +258,6 @@ export const workflowSettings: WorkflowSettings = { failurePolicy: { action: "stop" }, bindings: { "kinde.fetch": {}, - "kinde.secureFetch": {}, "kinde.env": {}, }, }; @@ -262,7 +268,7 @@ export default async function Workflow(event: onExistingPasswordProvidedEvent) { if (hasUserRecordInKinde) return; // Validate against Cognito ADMIN_USER_PASSWORD_AUTH - const cognitoResponse = await kinde.secureFetch( + const cognitoResponse = await kinde.fetch( `https://cognito-idp.${kinde.env.get("AWS_REGION")}.amazonaws.com/`, { method: "POST", @@ -300,7 +306,7 @@ export default async function Workflow(event: onExistingPasswordProvidedEvent) { Set the following environment variables: `AWS_REGION`, `COGNITO_CLIENT_ID`, `COGNITO_USER_POOL_ID`. You will also need to sign the request with AWS Signature V4 — add your signing logic or use a Lambda proxy that handles auth. -### Azure B2C variant +### 2D. Azure B2C variant Uses the Azure B2C Resource Owner Password Credentials (ROPC) token endpoint. @@ -319,7 +325,6 @@ export const workflowSettings: WorkflowSettings = { failurePolicy: { action: "stop" }, bindings: { "kinde.fetch": {}, - "kinde.secureFetch": {}, "kinde.env": {}, }, }; @@ -343,7 +348,7 @@ export default async function Workflow(event: onExistingPasswordProvidedEvent) { response_type: "token", }); - const azureResponse = await kinde.secureFetch( + const azureResponse = await kinde.fetch( `https://${tenant}.b2clogin.com/${tenant}.onmicrosoft.com/${policy}/oauth2/v2.0/token`, { method: "POST", @@ -378,7 +383,9 @@ Set the following environment variables: `AZURE_B2C_TENANT`, `AZURE_B2C_ROPC_POL git push ``` -## Step 2: Deploy the workflow +## 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. @@ -387,15 +394,20 @@ Set the following environment variables: `AZURE_B2C_TENANT`, `AZURE_B2C_ROPC_POL For full deployment instructions, see [Manage code and deployments](/workflows/manage-workflows/manage-code-and-deployments/). -## Step 3: Test the migration +### 2. Connect Kinde to your application -1. Sign in to your Kinde dashboard and go to **Authentication**. +1. Create an application and connect your codebase by [following these instructions](/get-started/guides/byo-code/). +2. Go to **Authentication**. 2. Enable **Email + password** if it isn't already enabled, and select **Save**. -3. Sign in as a test user (one who exists in your legacy system but not yet fully in Kinde). -4. Confirm the user appears in **Users** in Kinde after signing in. -5. Sign in as the same user a second time — they should authenticate directly through Kinde this time. -## Decommission your legacy system +### 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 appears in **Users** in Kinde after signing in. +4. 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: From 4488fd7dc9fa0f67ef26fb64d2e6de952e474430 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Mon, 11 May 2026 16:26:36 +0600 Subject: [PATCH 12/14] completed the drip feed tutorial --- .../drip-feed-migration.mdx | 552 ++++++++++-------- 1 file changed, 298 insertions(+), 254 deletions(-) diff --git a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx index 2adb25b29..9fdb9fb6c 100644 --- a/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx +++ b/src/content/docs/workflows/workflow-tutorials/drip-feed-migration.mdx @@ -15,6 +15,8 @@ topics: - workflows - workflow-tutorials - authentication + - user-management + - switch-to-kinde sdk: kinde infrastructure languages: - TypeScript @@ -24,15 +26,24 @@ audience: complexity: advanced keywords: - drip feed migration + - drip-feed migration - progressive migration - password migration workflow - existing password workflow + - user:existing_password_provided - zero downtime migration - - auth migration -updated: 2026-05-04 + - 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: "hello" +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. @@ -61,11 +72,13 @@ user3@example.com ### 2. Enable Enumeration protection -Go to your Kinde dashboard > **Settings > Attack protection > Enumeration protection** and turn it on. This is required for the workflow to function correctly. +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 will update the user password in Kinde, so you need to setup a Kinde Management API to do this. +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) @@ -82,23 +95,11 @@ This workflow will update the user password in Kinde, so you need to setup a Kin ### 4. Set up additional environment variables -You may need to add additional environment variables to your workflow, such as config details, API URLs, etc. Add them with the steps: - -1. Go to your Kinde dashboard > **Settings > Data management > Env variables** and set up your additional environment variables. +You may need to add additional environment variables to your workflow, such as API URLs or config values. Follow these steps: -If you need to store a sensitive value, ensure this is setup with **Sensitive** flag enabled to prevent accidental sharing. +1. Go to your Kinde dashboard > **Settings > Data management > Env variables** and add your environment variables. -### 5. Set up an encryption key - -Encryption keys protect sensitive data such as passwords when making secure API calls. Create an encryption key for your workflow: - -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 more on how to [Decrypt workflow‑encrypted payloads](/workflows/manage-workflows/encrypt-decrypt-workflows/#decrypt-workflowencrypted-payloads) here. +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 @@ -124,258 +125,293 @@ Learn more on how to [Decrypt workflow‑encrypted payloads](/workflows/manage-w ### 2A. Generic workflow (your custom backend) -Use this 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": {}, - }, -}; - -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. +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. -### 2B. Auth0 variant +To use the secure fetch, follow the steps: -Validates credentials using Auth0's Resource Owner Password Flow. - -```typescript -import { - onExistingPasswordProvidedEvent, - WorkflowSettings, - WorkflowTrigger, - createKindeAPI, -} 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": {}, - }, -}; - -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 auth0Response = await kinde.fetch( - `https://${kinde.env.get("AUTH0_DOMAIN")}/oauth/token`, - { - method: "POST", - responseFormat: "json", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - grant_type: "password", - username: providedEmail, - password, - audience: kinde.env.get("AUTH0_AUDIENCE"), - client_id: kinde.env.get("AUTH0_CLIENT_ID"), - client_secret: kinde.env.get("AUTH0_CLIENT_SECRET"), - }), - } - ); +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. - if (!auth0Response.ok) return; + 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": {}, + }, + }; - const kindeAPI = await createKindeAPI(event); - const { user } = await kindeAPI.post("/api/v1/user", { - profile: { email: providedEmail }, - identities: [{ type: "email", details: { email: providedEmail } }], - }); + export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; - await kindeAPI.put(`/api/v1/users/${user.id}/password`, { - password, - is_temporary_password: false, - }); -} -``` + // Already in Kinde — nothing to do + if (hasUserRecordInKinde) return; -Set the following [environment variables](/workflows/configuration/environment-variables-and-secrets/) in Kinde: `AUTH0_DOMAIN`, `AUTH0_AUDIENCE`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`. + // 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 }), + }); -### 2C. AWS Cognito variant + if (!legacyResponse.ok) return; -Uses Cognito's `ADMIN_USER_PASSWORD_AUTH` flow. Ensure this flow is enabled on your Cognito App Client before deploying. - -```typescript -import { - onExistingPasswordProvidedEvent, - WorkflowSettings, - WorkflowTrigger, - createKindeAPI, -} 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": {}, - }, -}; - -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 cognitoResponse = await kinde.fetch( - `https://cognito-idp.${kinde.env.get("AWS_REGION")}.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: kinde.env.get("COGNITO_CLIENT_ID"), - UserPoolId: kinde.env.get("COGNITO_USER_POOL_ID"), - AuthParameters: { - USERNAME: providedEmail, - PASSWORD: password, - }, - }), + // 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, + }); } - ); + ``` - if (!cognitoResponse.ok) return; +Check out the provider-specific variants below. - const kindeAPI = await createKindeAPI(event); - const { user } = await kindeAPI.post("/api/v1/user", { - profile: { email: providedEmail }, - identities: [{ type: "email", details: { email: providedEmail } }], - }); +### 2B. Auth0 variant - await kindeAPI.put(`/api/v1/users/${user.id}/password`, { - password, - is_temporary_password: false, - }); -} -``` +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, + }); + } + ``` -Set the following environment variables: `AWS_REGION`, `COGNITO_CLIENT_ID`, `COGNITO_USER_POOL_ID`. You will also need to sign the request with AWS Signature V4 — add your signing logic or use a Lambda proxy that handles auth. +### 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 -Uses the Azure B2C Resource Owner Password Credentials (ROPC) token endpoint. - -```typescript -import { - onExistingPasswordProvidedEvent, - WorkflowSettings, - WorkflowTrigger, - createKindeAPI, -} 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": {}, - }, -}; - -export default async function Workflow(event: onExistingPasswordProvidedEvent) { - const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; - - if (hasUserRecordInKinde) return; - - const tenant = kinde.env.get("AZURE_B2C_TENANT"); - const policy = kinde.env.get("AZURE_B2C_ROPC_POLICY"); - const clientId = kinde.env.get("AZURE_B2C_CLIENT_ID"); - const scope = kinde.env.get("AZURE_B2C_SCOPE"); - - 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(), - } - ); +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": {}, + }, + }; - if (!azureResponse.ok) return; + export default async function Workflow(event: onExistingPasswordProvidedEvent) { + const { providedEmail, password, hasUserRecordInKinde } = event.context.auth; - const kindeAPI = await createKindeAPI(event); - const { user } = await kindeAPI.post("/api/v1/user", { - profile: { email: providedEmail }, - identities: [{ type: "email", details: { email: providedEmail } }], - }); + if (hasUserRecordInKinde) return; - await kindeAPI.put(`/api/v1/users/${user.id}/password`, { - password, - is_temporary_password: false, - }); -} -``` + 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; -Set the following environment variables: `AZURE_B2C_TENANT`, `AZURE_B2C_ROPC_POLICY`, `AZURE_B2C_CLIENT_ID`, `AZURE_B2C_SCOPE`. + 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, + }); + } + ``` -5. Push your workflow code to GitHub: +### 3. Push your workflow code to GitHub ```bash git add . @@ -398,14 +434,18 @@ For full deployment instructions, see [Manage code and deployments](/workflows/m 1. Create an application and connect your codebase by [following these instructions](/get-started/guides/byo-code/). 2. Go to **Authentication**. -2. Enable **Email + password** if it isn't already enabled, and select **Save**. +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 appears in **Users** in Kinde after signing in. -4. Sign in as the same user a second time — they should authenticate directly through Kinde this time. +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 @@ -416,3 +456,7 @@ Once the drip-feed is running: - 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 From e0c4eae4e1433b9d1f2d086f2d8f4a8988f1245b Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Mon, 11 May 2026 17:00:41 +0600 Subject: [PATCH 13/14] coderabbit fix --- .../docs/get-started/switch-to-kinde/auth0-to-kinde.mdx | 6 +++--- .../get-started/switch-to-kinde/azure-b2c-to-kinde.mdx | 2 +- .../get-started/switch-to-kinde/create-users-with-api.mdx | 4 +--- .../get-started/switch-to-kinde/firebase-to-kinde.mdx | 8 ++++---- 4 files changed, 9 insertions(+), 11 deletions(-) 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 be9549b16..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 @@ -98,7 +98,7 @@ The extension appears in your list of installed extensions. The first time you l 4. Change the **Export Format** to **.json**. 5. Select **Export [X] Users**. Once complete, select **Download**. - You will have a JSON file to import into Kinde. + You will have an NDJSON (.json) file to import into Kinde ## Choose your migration method @@ -117,7 +117,7 @@ If your app hosts its own login form (email + password), you can push users to K 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: - ```json + ```http POST https://YOUR_DOMAIN/oauth/token { "grant_type": "password", @@ -186,7 +186,7 @@ Import objects via the [Kinde Management API](/kinde-apis/management/), or add t ### Can't get passwords from Auth0? -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](/get-started/switch-to-kinde/drip-feed-migration/) to avoid the export entirely. +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. ## Get 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 index 906f6062d..98e7dfb0a 100644 --- 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 @@ -67,7 +67,7 @@ The portal export includes basic user properties (email, display name, object ID 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,mail,userPrincipalName,accountEnabled +GET https://graph.microsoft.com/v1.0/users?$select=id,displayName,givenName,surname,mail,userPrincipalName,accountEnabled Authorization: Bearer {access_token} ``` 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 index 43cee6f3e..a9f7ec797 100644 --- 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 @@ -58,7 +58,7 @@ For automated drip-feed migration (no code changes to your app), see [Drip-feed - 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 prefered way to use the Management API (Node.js, Python, etc.) - [see usage guide](/developer-tools/kinde-api/access-token-for-api/). +- 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 @@ -114,8 +114,6 @@ Content-Type: application/json { "hashed_password": "$2a$10$examplehashvalue", "hashing_method": "bcrypt", - "salt": "", - "salt_position": "", "is_temporary_password": false } ``` 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 index 244d99b8e..776082f4d 100644 --- 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 @@ -80,9 +80,9 @@ Rename the fields in your Firebase JSON export to match what Kinde expects, then | `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 | `first_name` | | -| last name | `last_name` | | -| phone number | `phone` | | +| 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 | @@ -109,7 +109,7 @@ See the [bulk import guide](/get-started/switch-to-kinde/migrate-users-bulk-impo ### 4. Test the migration 1. Sign in to Kinde with a user from your Firebase export. -2. Verify they can sign in with their existing Firebase credentials. +2. Verify the user can access your application. 3. Notify users of any changes to their sign-in experience before going live. ## Get support From fb6a9639fd602dc4f01a8da97722f56d9ab93e59 Mon Sep 17 00:00:00 2001 From: Tamal Anwar Chowdhury Date: Mon, 11 May 2026 17:13:36 +0600 Subject: [PATCH 14/14] fix broken links --- .../docs/get-started/switch-to-kinde/aws-cognito-to-kinde.mdx | 2 +- src/content/docs/get-started/switch-to-kinde/clerk-to-kinde.mdx | 2 +- .../docs/get-started/switch-to-kinde/firebase-to-kinde.mdx | 2 +- .../docs/get-started/switch-to-kinde/supabase-to-kinde.mdx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) 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 index d8e3994e7..4bdaf1f66 100644 --- 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 @@ -76,7 +76,7 @@ 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/#step-3-prepare-your-csv) in the bulk import guide. +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 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 index fdf5fc940..4aa10a053 100644 --- 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 @@ -85,7 +85,7 @@ Rename the columns in your Clerk export to match what Kinde expects. The only re | `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/#step-3-prepare-your-csv) in the bulk import guide. +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.