# Migrate from Firebase Auth

> Move Firebase Authentication users into a SupaHost project with the admin API, keep their passwords using Firebase scrypt hashes, and handle Google and other social sign-ins.

Source: https://supahost.app/kb/migrate-from-firebase-auth · Updated 2026-11-11

You move Firebase Auth users into SupaHost by exporting them with the Firebase CLI and creating each one through the Supabase Auth admin API. Password users can keep their passwords, because Supabase Auth accepts Firebase's modified scrypt hashes. Social sign-in users simply sign in with the same provider again.

## Plan

- Decide how you'll map IDs. Supabase Auth user IDs are UUIDs and Firebase UIDs aren't, so each user gets a new ID. Keep the Firebase UID in `user_metadata` so you can rewrite ownership columns later (see [Migrate from Firestore](/kb/migrate-from-firestore)).
- Set up the target project's **Auth** tab first: Site URL, redirect URLs, and any OAuth providers your users rely on.
- If you also need to set "Skip email confirmation" or minimum password length, do it now in the **Sign-in & security** card.

## Export from Firebase

```bash
firebase auth:export users.json --format=JSON --project recipe-box-prod
```

Then open the Firebase console → **Authentication** → **Users** → the menu above the user list → **Password hash parameters**. Copy `base64_signer_key`, `base64_salt_separator`, `rounds` and `mem_cost`.

## Transform the hashes

Supabase Auth reads a Firebase scrypt hash in this layout (the `password_hash` field in supabase-js lists bcrypt, Firebase scrypt and argon2 as accepted formats):

```
$fbscrypt$v=1,n=<mem_cost>,r=<rounds>,p=1,ss=<base64_salt_separator>,sk=<base64_signer_key>$<salt>$<passwordHash>
```

`<salt>` and `<passwordHash>` come from each user in `users.json`. All values are standard base64; if your export uses URL-safe characters, swap `-` for `+` and `_` for `/`.

## Load the users

Run this once from your machine or a server, never in a browser:

```ts
import { createClient } from '@supabase/supabase-js'
import { readFileSync } from 'node:fs'

const admin = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!, {
  auth: { persistSession: false, autoRefreshToken: false },
})
const { users } = JSON.parse(readFileSync('users.json', 'utf8'))
const hp = { n: 14, r: 8, ss: 'Bw==', sk: process.env.FIREBASE_SIGNER_KEY! } // from the console

for (const u of users) {
  if (!u.email) continue
  const hash = u.passwordHash
    ? `$fbscrypt$v=1,n=${hp.n},r=${hp.r},p=1,ss=${hp.ss},sk=${hp.sk}$${u.salt}$${u.passwordHash}`
    : undefined
  const { error } = await admin.auth.admin.createUser({
    email: u.email,
    email_confirm: u.emailVerified ?? false,
    ...(hash ? { password_hash: hash } : {}),
    user_metadata: { firebase_uid: u.localId, name: u.displayName },
  })
  if (error) console.error(u.email, error.message)
}
```

Users without a password (Google, Apple, GitHub and so on) are created with a random password. When they sign in with the same provider and a verified email that matches, Supabase Auth links the new identity to the existing user.

Test with two or three of your own accounts before running the full list. If a hash is rejected, or you'd rather not move hashes at all, create users without `password_hash` and ask them to reset their password (`supabase.auth.resetPasswordForEmail`). A middle path is to keep Firebase running for a few weeks and, on first sign-in, check the password against Firebase and then set it on SupaHost with `auth.admin.updateUserById`.

## Switch the app

Replace Firebase calls with supabase-js: `signInWithEmailAndPassword` becomes `supabase.auth.signInWithPassword`, `signInWithPopup` becomes `supabase.auth.signInWithOAuth`, and `onAuthStateChanged` becomes `supabase.auth.onAuthStateChange`. Phone sign-in isn't available on SupaHost, so phone-only users need an email address.

## Verify

```sql
select count(*), count(*) filter (where email_confirmed_at is not null) as confirmed
from auth.users;
```

Compare with the export, then sign in as a password user and a social user.

## Related

- [Managing users (admin API)](/docs/auth/user-management)
- [Email and password sign-in](/docs/auth/passwords)
- [Social login (OAuth)](/docs/auth/social-login)
- [Linking identities](/docs/auth/identity-linking)
