Skip to content

Argon2 costs memory, not just time.

Bcrypt makes each guess slow. Argon2 makes each guess slow and also makes it allocate real memory, which is the expensive part of building cracking hardware. That is why it won the Password Hashing Competition and why it is the first recommendation for new projects.

Everything below this line runs locally

19 MiB per hash · 2 passes · 0 network requests

Check a password against an Argon2 hash

The encoded string carries its own parameters, so verification reads them back out and needs nothing else from you.

Verification also runs locally

Reading the encoded string

Everything needed to verify sits in the one value, the same way it does with bcrypt. The difference is that Argon2 has three parameters to record instead of one.

$argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG
└───┬───┘ └─┬─┘ └──────┬──────┘ └───┬────┘ └───────────────┬──────────────┘
    │       │          │            │                      digest
    │       │          │            salt, base64
    │       │          memory in KiB, iterations, lanes
    │       the Argon2 version, 19 is 0x13
    variant

In your own code

Node.js

import argon2 from 'argon2';

const hash = await argon2.hash(password, {
  type: argon2.argon2id,
  memoryCost: 19456,
  timeCost: 2,
  parallelism: 1
});

const ok = await argon2.verify(hash, candidate);

PHP

$hash = password_hash($password, PASSWORD_ARGON2ID, [
    'memory_cost' => 19456,
    'time_cost'   => 2,
    'threads'     => 1,
]);

if (password_verify($candidate, $hash)) { }

Python

from argon2 import PasswordHasher

ph = PasswordHasher(memory_cost=19456, time_cost=2, parallelism=1)
hash = ph.hash(password)
ph.verify(hash, candidate)

Widen the password column before you deploy any of this. An encoded Argon2id hash runs to about 100 characters, and a column sized for bcrypt at 60 will truncate it without complaining.

Questions people ask

Which variant should I use?
Argon2id. It combines the data independent access pattern of Argon2i with the data dependent one of Argon2d, which covers both side channel observation and time memory tradeoff attacks. Every current recommendation names the id variant specifically.
What do the parameters mean?
Memory is how much RAM a single hash allocates, and it is the parameter that costs an attacker the most. Iterations is how many passes are made over that memory. Parallelism is how many lanes run at once, and it should match how many cores you are willing to spend per hash.
Why is this slower here than in my application?
This runs as WebAssembly in a browser tab, which carries some overhead and gets no threads. A native library on a server will be faster at the same settings, so measure there before you decide your parameters are too heavy.
Do I need to store the salt separately?
No. The encoded output starting with $argon2id$ contains the version, all three parameters and the salt, in the same way a bcrypt string does. One column is enough.
Should I migrate from bcrypt to Argon2?
For a new project, start with Argon2id. For an existing bcrypt database that runs at a sensible cost factor, the gain is modest and the work is real, so raising your bcrypt cost is usually the better use of the time.

Next