import argon2 from "argon2";
const hash = await argon2.hash(password, { type: argon2.argon2id });
// "$argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash>"
const ok = await argon2.verify(hash, attempt);
Store a hash made by a slow, salted, adaptive password hashing function. Never store passwords in plaintext. Never use reversible encryption either.
A hash is a one-way fingerprint: you can check a password against it, but you can't turn it back into the password. Adaptive means you can make the function slower over time. OWASP's order of choice is:
- Argon2id first. It is memory-hard, which means each guess needs a lot of memory, so GPUs can't run many guesses at once.
- scrypt second.
- bcrypt for legacy systems.
- PBKDF2 when you need FIPS-140 compliance (a US government security standard).
Each password gets its own random salt. A salt is a random value mixed into the password before hashing. The library creates the salt for you. It stores the salt inside the hash string, together with the algorithm name and the cost settings. Salts stop precomputed tables of hashes from working. They also force attackers to crack each hash one by one.
Set the work factor (the cost setting) so hashing takes a noticeable amount of time on your hardware. Raise it as hardware gets faster. When you raise it, rehash each user's password at their next login.
At login, use the library's verify function. It hashes the typed password again with the stored settings and compares the result. Note: bcrypt only uses the first 72 bytes of the input.
- Hash passwords. Never encrypt them or store them in plaintext.
- Use Argon2id first, then scrypt, then bcrypt, and PBKDF2 when FIPS is required.
- Each password gets its own random salt, stored together with the hash.
- The work factor can be tuned. When you raise it, rehash passwords at next login.
- bcrypt ignores everything after the first 72 bytes of input.