Olympus Docs
CookbookPlatform migration

Migrate password hashes

Move from one password hash format to another

Kratos supports multiple password hash formats (Argon2id, bcrypt, pbkdf2, scrypt). You'd want to migrate when:

  • Importing from a system that uses a different format.
  • Upgrading from bcrypt to Argon2id for better security.
  • Standardizing across acquired user bases.

How Kratos stores hashes

In the identity_credentials table, the config field stores:

{
  "hashed_password": "$argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash>"
}

The format is identifiable by the prefix: $argon2id$, $2b$ (bcrypt), $pbkdf2-sha256$, $scrypt$.

Lazy migration

Kratos validates a password against whatever hash format is stored. So you can:

  1. Import users with their current (older) hashes.
  2. On successful login, rehash to the new format.

In kratos.yml:

selfservice:
  flows:
    login:
      after:
        password:
          hooks:
            - hook: rehash_password
              config:
                target_format: argon2id
                target_params:
                  memory: 65536
                  iterations: 3
                  parallelism: 4

(rehash_password is a hypothetical hook; check the Kratos version's docs for exact name.)

After this hook fires, the credential's hashed_password is updated to the new format. Future logins use the new format.

Eager migration

If you want to convert all hashes at once, you generally can't, you'd need the plaintext passwords (which you don't have).

Exceptions:

  • If the old format is reversible (which it shouldn't be for any modern hash), you could re-hash without users present. None of bcrypt/Argon2id/pbkdf2 are reversible.
  • Force every user through a password reset on first login (lazy but accelerated).

Forcing password reset

-- Mark all identities to require password change
UPDATE identities SET state = 'needs_password_reset';

On next login, Kratos detects the state and redirects to the recovery flow. After the user sets a new password, it's hashed in the current default format.

Mixed-format coexistence

Kratos handles mixed hash formats seamlessly. There's no urgency to fully convert; you can have some users on bcrypt and some on Argon2id indefinitely.

Verifying

After migration:

SELECT
  COUNT(*) FILTER (WHERE config->>'hashed_password' LIKE '$argon2id$%') AS argon2id,
  COUNT(*) FILTER (WHERE config->>'hashed_password' LIKE '$2b$%') AS bcrypt,
  COUNT(*) FILTER (WHERE config->>'hashed_password' LIKE '$pbkdf2%') AS pbkdf2,
  COUNT(*) AS total
FROM identity_credentials
WHERE type = 'password';

Choosing the target format

FormatProsCons
Argon2idMemory-hard, state-of-the-artNewer, less library support
bcryptWide support, matureLess memory-hard
pbkdf2-sha512FIPS-approvedLess computationally expensive (per-byte)
scryptMemory-hardLess mature library support

For new Olympus deployments: Argon2id, parameters m=65536, t=3, p=4.

For migrating: pick the format your security review prefers.

On this page