---
title: "What you take with you when you leave an auth provider"
summary: "Moving between sign-in providers needs no password reset if the export carries the hashes. What it must contain, and what EAuth imports."
author: "Samuel Krauss"
author_title: "Founder"
publisher: "Elchi Studios"
published: 2026-10-03
updated: 2026-10-03
url: https://elchi.dev/en/journal/what-you-take-with-you-when-you-leave-an-auth-provider
language: en
tags: ["eauth","migration","passwords"]
words: 1086
---

# What you take with you when you leave an auth provider

*By Samuel Krauss, Founder. Published 3 October 2026.*

> Moving between sign-in providers needs no password reset if the export carries the hashes. What it must contain, and what EAuth imports.

The moment you find out what a sign-in provider is worth is the day you want to leave it. If the export has your users' password hashes, you move them and nobody notices. If it does not, every user of yours gets a "please set a new password" mail from a company they have never heard of, and a share of them never comes back. This post is about the first kind of export, because that is the kind EAuth gives, and about what to look for before you sign up anywhere.

## Why the hash is enough

A password hash is not the password. It is the result of a slow, salted function that the provider stores instead of the password, and it can only be used one way: to check a candidate. Handing it to the next provider gives them exactly what the old one had, no more, and the next provider checks passwords against it the same way. The user's password never travels, and nobody learns it.

That is why a provider has no security reason to withhold the hashes. It has a commercial one.

## What the export has to contain

Ask for a file with, per account, the email address, whether it was confirmed, the display name, and the password hash in a standard string form that says which function made it. Argon2id in the PHC string format looks like `$argon2id$v=19$m=65536,t=3,p=2$...`; bcrypt starts with `$2a$`, `$2b$` or `$2y$`; scrypt and PBKDF2-SHA256 have shapes of their own, such as `$scrypt$` and Django's `pbkdf2_sha256$`. A hash without its parameters is useless, so the shape matters as much as the bytes.

Whether the address was confirmed matters more than it looks. A provider that receives an account marked unconfirmed should not simply trust it, and EAuth does not: more on that below.

You also want the rest of the account: which organisations a person belongs to and in which role, open invitations, which accounts sign in through a company's identity provider instead of a password, and the consents each person gave your application. Second factors are the exception, and it is worth knowing why before you ask for them: a passkey is bound to the provider's domain by design and would not work anywhere else, and a TOTP secret is better enrolled again than copied from one database into another. Users re-enrol their second factor after a migration, wherever they go.

## What EAuth exports

In the console, the owner and the admins of an application find **Export everything** on its **Users** page. It downloads the application as one JSON file: its settings, team, webhooks, organisations with members, roles, open invitations and single sign-on connection, the consents, and every account with its password hash as stored. No secrets travel with it: not the client secret, not the webhook signing secrets, not the private keys of the single sign-on connections. Those are credentials of our service, not your data.

The hash is Argon2id in the PHC format for anybody who has signed in with us, or the hash they were imported with if they have not. Each account also says whether its address is confirmed, whether it has a second factor, how many passkeys it has and, for single sign-on accounts, which identity provider it signs in through. That is the list of people to ask to re-enrol, ready before you move. The terms say the essential part in one sentence, 7.3: hashes are in the export in their original form, so you can migrate to another provider without forcing your users to reset their passwords. We consider being able to leave a feature, not a risk.

The export of a single person, for a request under Art. 15 or 20 GDPR, is on that person's page in the console, and contains no credentials: what is known about the person, not what lets somebody sign in as them.

## What EAuth imports

The other direction is the same door. The import takes a JSON array or a CSV with `email`, `password_hash` and optionally `display_name` and `email_verified`, up to 100,000 accounts and 25 MB per file, and recognises Argon2id, bcrypt, scrypt and PBKDF2-SHA256 by the shape of the hash, so you need no column saying which. The console checks the whole file first and shows what it found, how many accounts in which formats; nothing is written until you confirm. A file with one bad row is refused as a whole, with the row and the reason, and so is a row whose address already has an account at your application, because a half-imported user base is worse than none.

Imported accounts sign in with their old password from the moment the import finishes. At that first sign-in the password is hashed again with Argon2id, so a user base that arrives on bcrypt leaves bcrypt behind one person at a time, without anybody being asked to do anything. The console marks the accounts still on their imported hash. Nothing goes to your webhook for an import: your system already knows these people.

Two exceptions. An account imported with `email_verified` false, or without the column, is asked to confirm its address the first time it signs in, before your application gets it: since 3 October, no application gets an account whose address nobody has confirmed, imported or not. Mark as verified what the old provider had verified, and not more. And a password shorter than 12 characters or longer than 256 still signs in, but is not hashed again, because those are outside the lengths EAuth accepts for a new password; that account keeps its imported hash until the person changes the password, and the console mark stays.

## One thing to know about bcrypt

bcrypt uses only the first 72 bytes of a password. A user with a longer one has been signing in on those 72 bytes at the previous provider and keeps doing so until their first sign-in at EAuth, when the whole password is hashed with Argon2id. A small improvement nobody has to ask for, and a reason not to be surprised that a 90-character passphrase worked before and still does.

## Before you sign up anywhere

Read the export clause of the terms before the feature list. If the terms are silent about hashes, assume the answer is no. If there is a clause and it says "on request" or "subject to review", assume a delay measured in weeks at the moment you can least afford one. The clause you want says: at any time, without asking, in a documented format, hashes included.

## Sources

1. [Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html), OWASP, read 2026-10-03
2. [PHC Strings](https://c2sp.org/phc-strings), C2SP, read 2026-10-03
3. [RFC 9106: Argon2 Memory-Hard Function for Password Hashing and Proof-of-Work Applications](https://www.rfc-editor.org/rfc/rfc9106), IETF, read 2026-10-03
