Migrate from Supabase
Migrate from Supabase Auth
Supabase Auth is auth-as-a-feature inside the Supabase platform. Most teams migrate when they outgrow single-tenant and want first-class B2B orgs.
What you'll keep, what you'll lose, what you'll gain
- Keep: Email + verification status, display name (from
raw_user_meta_data.full_name), avatar URL, phone number, auth.identities (Google / GitHub / Apple / Microsoft / Facebook),raw_user_meta_dataandraw_app_meta_datapreserved as Authio user metadata. - Lose: Bcrypt password hashes (Authio is passwordless), Supabase sessions, Row-Level-Security policies (these live in Postgres, not in the auth provider — they keep working).
- Gain: First-class B2B orgs and memberships. SCIM. The risk engine. The audit stream as a separate service.
Orgs — bring your own graph
Supabase orgs are app-level (typically a public.orgs table you maintain), not auth-level. The importer supports either:
- Default: all users land under one synthetic
DefaultAuthio org. - With
--orgs-table: you provide a JSON mapping orgs → member emails. Authio creates each org and wires the memberships.
# orgs-table.json
{
"orgs": [
{
"external_id": "acme",
"name": "Acme Corp",
"slug": "acme",
"domain": "acme.com",
"members": [
{"email": "ada@acme.com", "role": "owner"},
{"email": "grace@acme.com", "role": "member"}
]
}
]
}Sessions
Supabase JWTs are not Authio-compatible. Users re-authenticate on next visit. Your Supabase Postgres database keeps working — only the auth provider changes.
Step-by-step: CLI
# 1) Dump auth.users + auth.identities to JSON.
psql "$SUPABASE_DB_URL" <<'SQL' --tuples-only --no-align > supabase.json
SELECT jsonb_build_object('users', jsonb_agg(jsonb_build_object(
'id', u.id, 'email', u.email,
'email_confirmed_at', u.email_confirmed_at,
'raw_user_meta_data', u.raw_user_meta_data,
'raw_app_meta_data', u.raw_app_meta_data,
'phone', u.phone, 'banned_until', u.banned_until,
'identities', (
SELECT jsonb_agg(jsonb_build_object(
'id', i.id, 'provider', i.provider, 'identity_data', i.identity_data))
FROM auth.identities i WHERE i.user_id = u.id
)
))) FROM auth.users u;
SQL
# 2) Optional: prepare an orgs-table.json mapping app-level orgs.
# 3) Dry-run.
authio import supabase --input ./supabase.json \
--orgs-table ./orgs-table.json --dry-run | jq '.stats'
# 4) Apply.
authio import supabase --input ./supabase.json --orgs-table ./orgs-table.jsonStep-by-step: dashboard wizard
Visit app.authio.com/migrate/supabase — the wizard accepts both the auth.users dump and an optional orgs-table.
Live import (paste an API token)
Paste a Supabase Personal Access Token + your project ref into the dashboard wizard. Authio pulls users (with their identity provider links) from api.supabase.com.
- Supabase dashboard → Account → Access Tokens → Generate new token.
- Grab your project ref — it's the subdomain of your project URL (
https://<project-ref>.supabase.co). - Paste both into the Authio wizard's Connect with API token tab. The probe hits
/v1/projects/{ref}. - Start the job; all users land in a default org (Supabase has no native org concept).
Tokens are encrypted at rest with envelope encryption and the credential row is auto-deleted within 24 hours.
Live import via the CLI
authio import supabase \
--live-token "$SUPABASE_PAT" \
--supabase-ref "$PROJECT_REF" \
--dry-runPost-migration checklist
- Swap
@supabase/auth-jsfor the Authio SDK. - Update JWT verification: Supabase JWTs → Authio JWKS.
- If your app gated rows by
auth.uid()in RLS policies, you'll need to map Authio user IDs back to Supabase user IDs — or change RLS to gate on email. - Send migration emails.
Authio's user IDs are different from Supabase user IDs. The importer records the Supabase ID in
source_external_ids on each Authio user, so you can join the two via a one-time SQL migration.