new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Better Auth · all subjects

better auth/migration

47 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Clerk migration invalidates all active sessions

When migrating from Clerk to Better Auth, all active sessions will be invalidated. Users will need to sign in again after the migration is complete.

Export Clerk user data as CSV for migration

To migrate users from Clerk, go to the Clerk dashboard and export users. This downloads a CSV file containing user data that should be saved as 'exported_users.csv' in the root of the project.

Clerk CSV export fields for migration

The Clerk CSV export contains the following fields for each user: id, first_name, last_name, username, primary_email_address, primary_phone_number, verified_email_addresses, unverified_email_addresses, verified_phone_numbers, unverified_phone_numbers, totp_secret, password_digest, and password_hasher.

Fetch Clerk users via API for external accounts during migration

In addition to the CSV export, fetch Clerk users via the Clerk API endpoint `https://api.clerk.com/v1/users?offset={i}&limit=500` using the CLERK_SECRET_KEY in the Authorization header to get external account information including provider details, scopes, and timestamps.

Clerk user data structure from API includes external accounts

The Clerk API returns user objects with properties: id, first_name, last_name, username, image_url, password_enabled, two_factor_enabled, totp_enabled, backup_code_enabled, banned, locked, lockout_expires_in_seconds, created_at, updated_at, and external_accounts array. Each external account has: id, provider, identification_id, provider_user_id, approved_scopes, email_address, first_name, last_name, image_url, created_at, updated_at.

Migrate user with conditional plugin fields

When creating a user during migration, include optional fields based on enabled plugins: for two-factor plugin add twoFactorEnabled, for admin plugin add banned, banExpires, and role='user', for username plugin add username, for phone-number plugin add phoneNumber and phoneNumberVerified.

Migrate Clerk account with credential provider

When a Clerk external account has provider='credential', create a Better Auth account with providerId='credential', issuer='local:credential', and include the password_digest from Clerk in the password field.

Safe date conversion for timestamps during migration

Use the safeDateConversion helper function during migration to handle timestamps. It validates that the timestamp is not empty, converts to a Date object, checks that the date is valid (not NaN), and verifies the year is between 2000 and 2100. Falls back to current date if any validation fails.

Run migration script with Bun

Execute the migration script using `bun run scripts/migrate-clerk.ts`. The script runs until completion or error, then exits with process.exit(0) on success or process.exit(1) on failure.

Pre-migration checklist

Before running the Clerk to Better Auth migration: (1) set up Better Auth in the project following the installation guide, (2) test the migration in a development environment first, (3) monitor the migration process for any errors, (4) verify the migrated data in Better Auth before proceeding, (5) keep Clerk installed and configured until the migration is complete.

Remove Clerk packages after migration verification

After verifying that all functionality works with Better Auth, remove Clerk dependencies with `pnpm remove @clerk/nextjs @clerk/themes @clerk/types`.

Supabase migration: installing packages

To migrate from Supabase Auth to Better Auth, install the `pg` package to connect to the database: `npm install pg`.

Supabase migration: basic database connection setup

Connect to your Supabase database using a Pool from the `pg` package. Pass `connectionString` from `process.env.DATABASE_URL` to `new Pool()`, then provide this Pool to betterAuth as the `database` option.

Supabase migration: enable emailAndPassword

Enable email and password authentication in the auth config by setting `emailAndPassword: { enabled: true }`. For email verification, add the `emailVerification` config separately.

Supabase migration: include social providers in config

Add all social providers used in Supabase to the auth config using the `socialProviders` option. Missing providers may cause user data loss during migration. Example: `socialProviders: { github: { clientId: ..., clientSecret: ... } }`.

Supabase migration: which plugins to add

Add plugins based on Supabase features you used: admin plugin if you have `is_super_admin` or `banned_until` fields; anonymous plugin if you used anonymous authentication; phoneNumber plugin if users signed up with phone numbers. Only include plugins for features you actually used.

Supabase migration: required additional fields

Add these required additional fields to the `user.additionalFields` config: userMetadata (json, required: false, input: false), appMetadata (json, required: false, input: false), invitedAt (date, required: false, input: false), lastSignInAt (date, required: false, input: false). These minimize data loss from Supabase Auth.

Supabase migration: run initial migration command

After setting up Better Auth config, run `npx auth migrate` to create the necessary tables in the public schema of your database.

Supabase migration: migration script environment variables

Set two environment variables for the migration script: FROM_DATABASE_URL (Supabase database connection string that reads from auth.users schema) and TO_DATABASE_URL (target Postgres database connection string that writes to public.user table). If migrating within the same Supabase database from auth schema to public schema, both URLs can be the same DATABASE_URL.

Supabase migration: CONFIG.batchSize default

The migration script's CONFIG.batchSize defaults to 5000 users per batch. Higher values speed up migration but use more memory. Recommended range is 5000-10000 for most cases.

Supabase migration: CONFIG.resumeFromId option

The migration script supports cursor-based pagination via CONFIG.resumeFromId, which defaults to null. Set it to a specific user ID to resume a migration from that point if it was interrupted.

Supabase migration: CONFIG.tempEmailDomain

Phone-only users in Supabase need an email for Better Auth. The migration script's CONFIG.tempEmailDomain defaults to 'temp.better-auth.com' and generates temporary emails in the format {phone_number}@{tempEmailDomain}.

Supabase migration: CONFIG.accountIssuers configuration

The migration script requires CONFIG.accountIssuers to map each social provider to its trusted issuer. For OAuth providers without a standard issuer, use the format 'local:oauth:<encoded providerId>' where providerId is percent-encoded. Example: github maps to 'local:oauth:github', google maps to 'https://accounts.google.com'.

Supabase migration: password hashing algorithm change

Supabase uses bcrypt for password hashing while Better Auth defaults to scrypt. To use bcrypt for password verification after migration, install bcrypt (`npm install bcrypt`) and configure the password option in emailAndPassword with custom `hash` and `verify` functions.

Supabase migration: bcrypt password configuration example

Configure password hashing in the auth config as: `emailAndPassword: { enabled: true, password: { hash: async (password) => await bcrypt.hash(password, 10), verify: async ({ hash, password }) => await bcrypt.compare(password, hash) } }`.

Supabase migration: client API mapping

Map these Supabase auth API calls to Better Auth equivalents: supabase.auth.signUp → authClient.signUp.email; supabase.auth.signInWithPassword → authClient.signIn.email; supabase.auth.signInWithOAuth → authClient.signIn.social; supabase.auth.signInAnonymously → authClient.signIn.anonymous; supabase.auth.signOut → authClient.signOut; supabase.auth.getSession → authClient.getSession (or authClient.useSession for reactive state).

Supabase migration: migration invalidates active sessions

The migration process will invalidate all active sessions. Users will need to sign in again after the migration.

Supabase migration: 2FA and RLS not covered

This migration guide does not currently cover migrating two-factor authentication (2FA) or Row Level Security (RLS) configurations, though both should be possible with additional steps.

Supabase migration: back up database before migrating

Back up your database before running any migration scripts. The migration modifies production data. Create a full backup of both your Supabase database and target database before proceeding.

Supabase migration: run migration script command

Run the migration script with `npx tsx migration.ts`. Other TypeScript runners can also be used, such as `bun migration.ts`, `ts-node migration.ts`, or compile to JS first.

Supabase migration: keyset pagination for large datasets

The migration script uses keyset pagination (cursor-based) to efficiently handle large datasets without loading everything into memory. For very large migrations (500k+ users), increase Node's memory limit with `NODE_OPTIONS="--max-old-space-size=8192"`.

Supabase SSO migration: install SSO plugin

Install the Better Auth SSO package with `npm install @better-auth/sso`, then import and add the `sso()` plugin to your auth configuration's plugins array.

Supabase SSO migration: run SSO database migration

After adding the SSO plugin to your auth config, run `npx auth migrate` to create the `ssoProvider` table.

Supabase SSO migration: export providers from Supabase

Export SSO providers from Supabase using: `supabase sso list --project-ref <your-project-ref>` to list providers, and `supabase sso show <provider-id> --project-ref <your-project-ref> -o json > sso-provider.json` to export full details including metadata_xml. Use `sso show` (not `sso list`) to get the metadata_xml field.

Supabase SSO provider export structure

A Supabase SSO provider export includes: id (provider UUID), saml object with entity_id, metadata_url, metadata_xml, attribute_mapping with keys mapping (email, first_name, last_name etc. to SAML attribute names), name_id_format, and domains array with domain objects containing id and domain string.

Supabase SSO migration: IdP metadata transformation

Better Auth requires inline IdP metadata XML, not a URL. If Supabase provides only metadata_url, fetch the XML first using the URL before migrating the provider.

Supabase SSO migration: SAML attribute mapping

When migrating SSO providers, map Supabase attribute names to Better Auth fields: email field (default 'email'), name field (default 'displayName'), firstName field (default 'givenName'), lastName field (default 'surname'). Supabase supports both single attribute names and arrays of names; take the first available.

Supabase SSO migration: Better Auth SP metadata URL

Better Auth's Service Provider (SP) metadata is located at: `https://yourapp.com/api/auth/sso/saml2/sp/metadata?providerId=<providerId>`. The providerId should be in format 'sso-<supabase-provider-id>'.

Supabase SSO migration: update IdP settings after migration

After migrating SSO providers, update your Identity Provider settings: change ACS URL from `https://<project>.supabase.co/auth/v1/sso/saml/acs` to `https://yourapp.com/api/auth/sso/saml2/sp/acs/<providerId>`; change Entity ID from `https://<project>.supabase.co/auth/v1/sso/saml/metadata` to `https://yourapp.com/api/auth/sso/saml2/sp/metadata?providerId=<providerId>`. Replace <providerId> with your migrated provider ID.

Supabase SSO migration: trusted SAML account identities

Better Auth identifies SAML accounts by the IdP entity ID from provider metadata and the signed NameID. Supabase exports do not contain enough verified data to derive these safely. Create an operator-reviewed mapping from legacy SSO identity to IdP entity ID and signed NameID before migrating accounts. Do not substitute service-provider entity_id, email addresses, or profile sub claims.

Supabase SSO migration: client code update

Update Supabase SSO calls to Better Auth: replace `supabase.auth.signInWithSSO({ domain: 'company.com' })` with `authClient.signIn.sso({ domain: 'company.com', callbackURL: '/dashboard' })`. Better Auth also supports sign-in by email (domain extracted automatically) or by providerId directly.

Supabase SSO migration: install ssoClient plugin

In your Better Auth client code, import ssoClient from '@better-auth/sso/client' and add it to the createAuthClient plugins array: `const authClient = createAuthClient({ plugins: [ssoClient()] })`.

Supabase SSO migration: SSO sign-in options

Better Auth SSO client supports three sign-in methods: by domain (`authClient.signIn.sso({ domain: 'company.com', callbackURL: '/dashboard' })`), by email with auto-extracted domain (`authClient.signIn.sso({ email: 'user@company.com', callbackURL: '/dashboard' })`), or by provider ID (`authClient.signIn.sso({ providerId: 'sso-550e8400-...', callbackURL: '/dashboard' })`).

Supabase SSO migration: troubleshoot signature errors

If you see SAML signature validation errors during SSO testing, the issue is likely an outdated IdP certificate. Check the IdP metadata URL for the latest certificate, as some identity providers rotate certificates periodically.

Supabase SSO migration: troubleshoot attribute mapping

If user attributes are not populating correctly after SSO migration, inspect the SAML assertion from your IdP using browser developer tools. Update the `mapping` field in your `samlConfig` to match the exact attribute names your IdP sends.

Supabase SSO migration: multiple domains per provider

If you have multiple domains for a single SSO provider, separate them with commas in the `domain` field: 'company.com,company.org'.

Supabase SSO migration: SSO invalidates active sessions

SSO migration requires updating your Identity Provider configuration with new callback URLs. Existing SSO sessions will be invalidated during the migration, so plan for a brief cutover window.

Give your agent this brain