Migrate from Stytch
Migrate from Stytch
Stytch B2B's data model is similar to Authio's — shared members across organizations by email. The migration is mostly a 1:1 mapping.
Credit where it's due: Stytch B2B got the multi-org-by-email model right. If you're migrating from Stytch, it's not because of the data model — it's usually about pricing, the breadth of features (SCIM, custom domains, the risk engine), or the desire to consolidate consumer + B2B under one provider.
What you'll keep, what you'll lose, what you'll gain
- Keep: Organizations + slugs, members + roles (admin → Authio admin), trusted / untrusted metadata, MFA enrolled flag, SSO connection records.
- Lose: Stytch sessions (users re-auth), AuthKit passwords (Authio is passwordless), TOTP secrets (only the enrolled flag preserved).
- Gain: Custom-domain hosted UI, the audit stream as a separate service, the risk engine, fine-grained authorization.
B2B vs Consumer
Stytch ships two products: B2B (orgs + members) and Consumer (flat users). The importer auto-detects:
- B2B export — a JSON object with
organizations[]at the top, each withmembers[]inside. Maps 1:1 to Authio orgs + users + memberships. - Consumer export — a JSON array of users. All users land under one synthetic
DefaultAuthio org.
Sessions
Stytch sessions are dropped. Users sign in via passkey or magic-link on next visit.
Step-by-step: CLI (B2B)
# 1) Fetch orgs + members.
H="Authorization: Bearer $STYTCH_SECRET"
H2="content-type: application/json"
orgs=$(curl -s -X POST "https://api.stytch.com/v1/b2b/organizations/search" -H "$H" -H "$H2" -d '{}')
# 2) For each org, fetch members and attach.
echo "$orgs" | jq -c '.organizations[]' | while read o; do
oid=$(echo "$o" | jq -r .organization_id)
members=$(curl -s -X POST "https://api.stytch.com/v1/b2b/organizations/$oid/members/search" -H "$H" -H "$H2" -d '{}')
echo "$o" | jq --argjson m "$members" '. + {members: $m.members}'
done | jq -s '{organizations: ., sso_connections: []}' > stytch.json
# 3) Dry-run.
authio import stytch --input ./stytch.json --dry-run | jq '.stats'
# 4) Apply.
authio import stytch --input ./stytch.jsonStep-by-step: CLI (Consumer)
curl -s -X POST "https://api.stytch.com/v1/users/search" \
-H "Authorization: Bearer $STYTCH_SECRET" \
-H "content-type: application/json" -d '{}' \
| jq '.results' > stytch.json
authio import stytch --input ./stytch.jsonStep-by-step: dashboard wizard
Visit app.authio.com/migrate/stytch.
Live import (paste an API token)
Skip the bundle assembly. Paste your Stytch Project ID + Project Secret into the dashboard wizard and Authio walks every B2B organization and member for you.
- Stytch dashboard → API Keys → copy your live Project ID and Project Secret (used as HTTP Basic auth).
- In Authio: Migrate from Stytch → Connect with API token. Paste both. The probe hits
/v1/b2b/organizations/search. - Start the job; progress updates per-org as the worker fans out into
members/search.
Live import via the CLI
authio import stytch \
--live-token "$STYTCH_PROJECT_SECRET" \
--stytch-project-id "$STYTCH_PROJECT_ID" \
--stytch-secret "$STYTCH_PROJECT_SECRET" \
--dry-runPost-migration checklist
- Swap Stytch SDK for the Authio SDK; the patterns are similar.
- Recreate SSO connections (the plan lists Stytch's connection IDs for cross-reference).
- Send migration emails.
trusted_metadata and untrusted_metadata distinction is preserved in Authio user metadata under those exact keys, so your app code can continue to use the same access pattern.