workos-migrate-clerk

WorkOS Migration: Clerk

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "workos-migrate-clerk" with this command: npx skills add workos/skills/workos-skills-workos-migrate-clerk

WorkOS Migration: Clerk

Step 1: Fetch Documentation (BLOCKING)

STOP. Do not proceed until complete.

WebFetch: https://workos.com/docs/migrate/clerk

The migration guide is the source of truth. If this skill conflicts with the guide, follow the guide.

Step 2: Pre-Migration Assessment (Decision Tree)

User authentication methods? | +-- Passwords --> Step 3A: Export passwords via Clerk API | +-- Social (Google/Microsoft) --> Skip to Step 4 (auto-link by email) | +-- Mixed --> Complete both paths

Organization structure? | +-- B2B with orgs --> Step 5: Export organizations | +-- B2C (no orgs) --> Skip Step 5

MFA enabled? | +-- SMS-based --> Users MUST re-enroll (WorkOS does not support SMS) | +-- TOTP-based --> Users MUST re-enroll (cannot export secrets)

Critical limitation: Clerk TOTP secrets and SMS configurations cannot be exported. All MFA users must re-enroll after migration.

Step 3A: Export Passwords (If Password Auth Used)

Via Clerk Backend API

Use Clerk's user export API to generate CSV with password hashes.

Verify: CSV contains password_digest column with bcrypt hashes before proceeding.

Important: Clerk does NOT export plaintext passwords. The CSV contains bcrypt hashes only.

Field Mapping (Password Export)

Clerk CSV Column --> WorkOS User Creation Field email_addresses --> email (primary) first_name --> first_name last_name --> last_name password_digest --> password_hash (with password_hash_type='bcrypt')

Step 3B: Handle Multi-Email Users

Clerk exports multiple emails pipe-separated:

"email_addresses": "john@example.com|john.doe@example.com"

Problem: Export does NOT indicate which is primary.

Solution: If multiple emails detected, fetch User object via Clerk User API to determine primary email before WorkOS import.

Step 4: Import Users into WorkOS

Rate Limit Warning

User creation is rate-limited. Check https://workos.com/docs/reference/rate-limits for current limits.

Pattern: Batch imports with delay between batches to avoid 429 errors.

Import Method (Choose One)

Option A: Use WorkOS migration tool: https://github.com/workos/migrate-clerk-users

Option B: Write custom import using WorkOS User Creation API

User Creation Parameters

For each Clerk user, call Create User API:

Required fields:

  • email

  • from Clerk email_addresses (primary only)

  • first_name

  • from Clerk first_name

  • last_name

  • from Clerk last_name

Password import (if exported):

  • password_hash_type

  • MUST be 'bcrypt' (Clerk's hash algorithm)

  • password_hash

  • from Clerk password_digest field (the bcrypt hash)

Example payload:

{ "email": "user@example.com", "first_name": "John", "last_name": "Doe", "password_hash_type": "bcrypt", "password_hash": "$2a$10$..." }

Verification command:

Check that imported user can authenticate

curl -X POST https://api.workos.com/user_management/authenticate
-H "Authorization: Bearer $WORKOS_API_KEY"
-d "email=user@example.com"
-d "password=<test_password>"

Step 5: Migrate Social Auth Users

Supported Providers

WorkOS supports Google OAuth and Microsoft OAuth. Configure providers in WorkOS Dashboard before migration.

Auto-Linking Mechanism

No manual action required for social auth users. WorkOS auto-links by email:

  • User signs in with Google/Microsoft via WorkOS

  • WorkOS extracts email from OAuth provider

  • WorkOS matches email to existing user created in Step 4

  • User is linked automatically

Critical: Ensure users from Step 4 have correct email addresses. Mismatch = failed auto-link.

Step 6: Create Organizations (If B2B)

Export Clerk Organizations

Use Clerk Organization List API to paginate through organizations.

Pattern:

// Pseudocode - use Clerk Backend SDK let hasMore = true; let offset = 0; while (hasMore) { const { data, totalCount } = await clerkClient.organizations.getOrganizationList({ limit: 100, offset }); // Process data hasMore = (offset + data.length) < totalCount; offset += data.length; }

Create WorkOS Organizations

For each Clerk organization, call Create Organization API.

Minimum required:

  • name
  • organization display name

Verification command:

List created organizations

curl https://api.workos.com/organizations
-H "Authorization: Bearer $WORKOS_API_KEY"

Step 7: Add Organization Memberships

Export Clerk Memberships

Use Clerk Membership List API for each organization.

Create WorkOS Memberships

For each membership, call Create Organization Membership API.

Required parameters:

  • user_id

  • WorkOS user ID (from Step 4 import mapping)

  • organization_id

  • WorkOS organization ID (from Step 6 mapping)

Critical: Maintain mapping of Clerk user IDs → WorkOS user IDs and Clerk org IDs → WorkOS org IDs for this step.

Step 8: Handle MFA Re-Enrollment

SMS-Based MFA (Not Supported)

WorkOS does NOT support SMS-based MFA due to security concerns.

Users with SMS MFA MUST:

  • Re-enroll using TOTP authenticator app, OR

  • Use Magic Link authentication instead

Notify affected users before migration.

TOTP-Based MFA (Cannot Migrate)

Clerk does not export TOTP secrets. All TOTP users must re-enroll.

Re-enrollment flow:

  • User signs in with password (migrated in Step 4)

  • User navigates to MFA settings

  • User scans new QR code to enroll TOTP

See WorkOS MFA guide for enrollment implementation.

Verification Checklist (ALL MUST PASS)

Run these checks before marking migration complete:

1. Verify users imported

curl https://api.workos.com/user_management/users
-H "Authorization: Bearer $WORKOS_API_KEY" | jq '.data | length'

Should match Clerk user count

2. Test password authentication for imported user

curl -X POST https://api.workos.com/user_management/authenticate
-H "Authorization: Bearer $WORKOS_API_KEY"
-d "email=test@example.com"
-d "password=<known_password>"

Should return 200 with user object

3. Verify organizations imported (if B2B)

curl https://api.workos.com/organizations
-H "Authorization: Bearer $WORKOS_API_KEY" | jq '.data | length'

Should match Clerk organization count

4. Verify memberships created (if B2B)

curl "https://api.workos.com/user_management/organization_memberships?user_id=&#x3C;user_id>"
-H "Authorization: Bearer $WORKOS_API_KEY"

Should return memberships for test user

5. Test social auth auto-link

Sign in via Google/Microsoft with email matching imported user

Should link to existing WorkOS user, not create duplicate

Error Recovery

"User already exists" on import

Cause: Duplicate email addresses in import batch or re-running import.

Fix: Check for existing user before creation:

curl "https://api.workos.com/user_management/users?email=user@example.com"
-H "Authorization: Bearer $WORKOS_API_KEY"

If exists, use Update User API instead of Create.

"Invalid password hash" on user creation

Cause:

  • password_hash_type not set to 'bcrypt'

  • password_hash field missing $2a$ prefix (malformed bcrypt hash)

Fix: Verify Clerk export contains valid bcrypt hashes. They MUST start with $2a$ or $2b$ .

Rate limit 429 on batch import

Cause: Exceeding WorkOS user creation rate limit.

Fix: Add delay between batches:

// Pseudocode for (const batch of userBatches) { await importBatch(batch); await sleep(1000); // 1 second delay between batches }

Check https://workos.com/docs/reference/rate-limits for current limits and adjust delay accordingly.

Social auth user creates duplicate instead of linking

Cause: Email mismatch between WorkOS user and OAuth provider email.

Fix:

  • Check OAuth provider email: curl the OAuth token endpoint

  • Check WorkOS user email: Use Users API

  • If mismatch, update WorkOS user email via Update User API

Organization membership creation fails with "User not found"

Cause: Attempting to create membership before user import completes, or using wrong user ID.

Fix:

  • Verify user exists: curl Users API with email filter

  • Ensure you're using WorkOS user ID, not Clerk user ID

  • Maintain ID mapping file: clerk_user_id → workos_user_id

MFA users cannot sign in after migration

Expected behavior. All MFA users MUST re-enroll:

  • Disable MFA requirement temporarily in WorkOS Dashboard

  • Notify users to re-enroll via app settings

  • Re-enable MFA requirement after re-enrollment window

Related Skills

  • workos-authkit-nextjs - Integrate WorkOS AuthKit into Next.js after migration

  • workos-authkit-react - Integrate WorkOS AuthKit into React after migration

  • workos-mfa - Implement MFA re-enrollment flow

  • workos-magic-link - Alternative to password auth for users who can't migrate

  • workos-api-authkit - Core AuthKit API reference for custom integrations

  • workos-api-organization - Organization management API details

  • workos-sso - Configure SSO for migrated organizations

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

workos

No summary provided by upstream source.

Repository SourceNeeds Review
-150
workos
General

workos-authkit-nextjs

No summary provided by upstream source.

Repository SourceNeeds Review
General

workos-authkit-base

No summary provided by upstream source.

Repository SourceNeeds Review