Skip to main content

Data export & migration

How to export your data out of IdentSphere, and how to import data in.

Export

The CLI ships an export command that produces a single tarball with one file per table, in NDJSON format:

identsphere export --database-url "$DATABASE_URL" --schema identsphere --output ./export.tar.gz

The tarball contains:

users.ndjson
organizations.ndjson
organization_memberships.ndjson
member_invitations.ndjson
user_sessions.ndjson
user_passkeys.ndjson
user_recovery_codes.ndjson
email_verification_tokens.ndjson
email_otp_challenges.ndjson
trusted_browsers.ndjson
platform_admins.ndjson
audit_logs.ndjson
api_keys.ndjson

Each file is one JSON object per line, exactly matching the column shape. Hashed credentials (password_hash, mfa_secret, recovery_codes.code_hash) are preserved — the export is portable to another IdentSphere deployment without re-onboarding users.

::: warning Sensitive content The export contains every secret the SDK persists. Treat the tarball as a top-tier credential and encrypt it at rest. :::

Import

For now, import is "use psql." The export shape mirrors \copy input, so loading a fresh deployment is:

psql "$DATABASE_URL" -c "CREATE SCHEMA IF NOT EXISTS IdentSphere;"
identsphere migrate up --database-url "$DATABASE_URL" --schema identsphere

for f in *.ndjson; do
table="${f%.ndjson}"
psql "$DATABASE_URL" -c "\\copy IdentSphere.${table} FROM '${f}' WITH (FORMAT csv, ESCAPE '\"')"
done

A first-class IdentSphere import command lands in a later release.

Migrating from another auth system

The most common case: migrating from a legacy auth system (Devise, NextAuth, custom rails auth, etc.).

Password hashes

IdentSphere's verifier accepts bcrypt hashes directly. To migrate:

  1. Export email + bcrypt_hash from the legacy system.
  2. INSERT INTO IdentSphere.users (id, email, password_hash, organization_id, role, status, …) with the bcrypt hash in password_hash.
  3. On first login, the SDK silently rehashes to Argon2id.

Existing organizations / tenants

Map your existing tenant table 1:1 to IdentSphere.organizations. The id can be reused (preserves foreign-key relationships in host tables).

User sessions

DO NOT migrate sessions. The session-token format is IdentSphere-specific. Force a re-login at migration cutover.

MFA secrets

If the source system also uses RFC 6238 TOTP with base32 secrets, you can copy the secret into users.mfa_secret and set mfa_enabled = true. The SDK uses SHA-1, 6 digits, 30s — verify the source uses the same.

OAuth / social logins

IdentSphere doesn't keep an external_id mapping for social logins; the email is the linking key. If the legacy system mapped (provider, external_id) → user, you need to ensure the legacy user's email matches the email the provider returns today (this is usually fine; emails are stable).

GDPR delete

A "right to be forgotten" delete is host-implemented:

BEGIN;
-- Audit entries: anonymize, don't delete (compliance requires retention).
UPDATE IdentSphere.audit_logs SET actor_id = NULL, metadata = '{}'
WHERE actor_id = '$USER_ID';

-- Sessions / tokens: hard delete.
DELETE FROM IdentSphere.user_sessions WHERE user_id = '$USER_ID';
DELETE FROM IdentSphere.user_passkeys WHERE user_id = '$USER_ID';
DELETE FROM IdentSphere.user_recovery_codes WHERE user_id = '$USER_ID';
DELETE FROM IdentSphere.email_verification_tokens WHERE user_id = '$USER_ID';
DELETE FROM IdentSphere.email_otp_challenges WHERE user_id = '$USER_ID';
DELETE FROM IdentSphere.trusted_browsers WHERE user_id = '$USER_ID';
DELETE FROM IdentSphere.organization_memberships WHERE user_id = '$USER_ID';

-- User row: anonymize email + clear PII.
UPDATE IdentSphere.users SET
email = id::text || '@anonymized.invalid',
password_hash = '',
display_name = NULL,
phone_number = NULL,
avatar_url = NULL,
bio = NULL,
preferences = NULL,
status = 'deleted'
WHERE id = '$USER_ID';
COMMIT;

Avatars in object storage need a separate sweep.

Backup

Standard Postgres backups (pg_dump, WAL archiving) cover the entire schema. The SDK doesn't ship a separate backup mechanism.