What is Argon2id?
Argon2id is a password-hashing function derived from Argon2, the algorithm selected as the winner of the Password Hashing Competition (PHC) in 2015. The competition — organized by cryptographers including Jean-Philippe Aumasson — asked the community to design a password hashing scheme that could withstand the two threats that had broken its predecessors: fast GPU brute-forcing and cheap specialized hardware. Argon2id is the hybrid variant of Argon2, and the exact configuration the PHC winners and OWASP recommend for ordinary password storage.
Two design ideas set Argon2 apart from earlier KDFs. First, memory hardness: computing a hash must consume a large, tunable amount of RAM, so no hardware shortcut can make guesses dramatically cheaper. Second, tunable parallelism: work can fan out across up to 16 lanes, letting a single login cost seconds of sequential CPU time on ordinary hardware. The full state — password, salt, version, and parameters — is folded into a single encoded string, so a system storing Argon2 hashes needs nothing more than a text column to verify a login later.
How Argon2 works, step by step
1. Fill the memory buffer
Argon2 first derives an initial state from the password and a random salt using
BLAKE2b. It then fills a buffer of m KiB — split across p
parallel lanes — block by block. Each 1 KiB block is produced by permuting one or more
previously written blocks: the current block plus a reference chosen from the blocks
already written in this pass.
2. Overwrite it, t times
With the buffer full, Argon2 runs t passes, each pass overwriting every block. The
permutation function inside each block is a compression round that mixes XOR and modular
addition (a structure close to a fast, memory-hard hash like the one used by Zcash's
Equihash family). Because every block's output depends on blocks computed earlier in the same
run, an attacker cannot skip the fill step: the memory contents encode the password, and any
shortcut that drops blocks breaks the result.
3. Squeeze the tag
After the final pass, Argon2 feeds the last block of each lane, the password length, the salt, and the parameters into a final BLAKE2b step to produce the tag — the derived key. With the encoded output format, that tag is Base64-encoded and appended to a self-describing header, which is why an Argon2id string can carry everything needed to re-derive it later.
Argon2d, Argon2i, Argon2id — which variant?
The three Argon2 variants differ only in how each block chooses its references, and that small difference has real security consequences:
- Argon2d picks references data-dependently — using the previous block's contents as the address of the next source block. This maximizes resistance to time-memory tradeoff attacks and GPU cracking, but the data-dependent addressing leaks timing information through CPU cache behavior. A process that can co-locate on your machine and observe cache misses could, in principle, learn about the password.
- Argon2i picks references data-independently, using a fixed pseudo-random schedule derived only from the salt and inner state. This is immune to cache-timing side channels, which made it the PHC entrants' safe choice — but an attacker with a large enough budget can exploit the predictability with a time-memory tradeoff attack at lower cost than against Argon2d.
- Argon2id hybridizes the two: the first half of the first pass uses data-independent (Argon2i-style) addressing, and everything after is data-dependent (Argon2d-style). It captures most of Argon2i's side-channel resistance while keeping most of Argon2d's tradeoff resistance. For password hashing on multi-user servers, it is the configuration everyone — the PHC, OWASP, and RFC 9106 — recommends you actually use.
The rule of thumb: use argon2id for password storage and password-based key
derivation. Reaching for Argon2i is defensible only in threat models dominated by
side-channel attacks (shared, untrusted execution environments); Argon2d is reserved for
environments where even an active attacker cannot observe timing — a rare guarantee.
m, t, p — the three knobs that control the cost
Argon2's cost is described by three integers, all exposed in this tool:
-
m— memory in KiB. The buffer size. Every hash must actually allocate and write this much memory, so it is the parameter that most directly determines brute-force cost. Raisingmfrom 19 MiB to 64 MiB does not merely slow a targeted attack — it changes which hardware is viable at all, because GPUs have limited on-card memory and memory bandwidth is shared across every concurrent guess. -
t— iterations. Number of full passes over the buffer. Each extra pass multiplies compute time and memory traffic without consuming more RAM. On a CPU,tis cheap and safe to raise when you need more work than memory allows; the tradeoff is that hightdoes slightly less to resist memory-as-ASIC attackers than a corresponding increase inm. -
p— parallelism / lanes. Number of independent lanes the memory buffer is split across; they are combined at the end into the single final block. Higherplets a server with many cores service logins in less wall-clock time per CPU core, at no security cost. It is safe to keep at 1 if you only sign in on one device; large deployments benefit from 4.
The fourth field in this tool, hash length, sets the tag size in bytes. The default of 32 bytes (256 bits) is a deliberate choice: it is the maximum supported by the reference implementation for standard password hashing and gives a comfortable margin against brute-forcing the tag itself. Lower values (16) match older applications; higher values add no security for password storage.
OWASP & RFC 9106 — sane starting points
Instead of reasoning about m, t, p from scratch, start from the two published recommendations this tool's presets follow:
| Source | Memory | t | p | Use case |
|---|---|---|---|---|
| OWASP minimum | 19 MiB (m=19456) | 2 | 1 | Absolute floor for any Argon2id deployment |
| OWASP recommended | 64 MiB (m=65536) | 3 | 4 | New systems with normal login volume |
| RFC 9106 interactive | 64 MiB (m=65536) | 3 | 4 | Low-memory configuration for interactive logins |
| High security | 128 MiB (m=131072) | 4 | 4 | Backend/admin or batch hashing with generous RAM |
The OWASP Password Storage Cheat Sheet has treated these figures as the reference guidance since 2021: 19 MiB / t=2 / p=1 is the documented floor, and 64 MiB / t=3 / p=4 is the recommended default for new applications. RFC 9106 (the Argon2 RFC) independently describes a comparable interactive-login configuration. Any configuration at or above the floor is a defensible choice; the presets in this tool exist so you can toggle between the two published benchmarks and a high-security option without doing the math by hand.
Argon2id vs bcrypt vs scrypt vs PBKDF2
| Argon2id | bcrypt | scrypt | PBKDF2 | |
|---|---|---|---|---|
| Year | 2015 | 1999 | 2009 | 2000 |
| Deliberate cost | CPU + memory + threads | CPU (iterations) | CPU + memory | CPU (iterations) |
| GPU/ASIC resistance | Very high | Moderate | High | Low |
| Side-channel sensitivity | Low (Argon2id hybrid) | Low | Low | Low |
| Input limits | None practical | 72 bytes | None practical | None practical |
| Library availability | Growing (most languages) | Every major language | Most languages | Every major language |
| OWASP recommendation | Recommended | Accepted (legacy) | Accepted | Accepted |
The table explains the modern hierarchy in one glance. PBKDF2 remains mandatory in some compliance regimes but is weakest against modern hardware. bcrypt adds salt and CPU deliberate slowness but caps inputs at 72 bytes and has no memory cost at all. scrypt introduced memory-hardness and is good in constrained environments, but its memory addressing is data-dependent-only and it never received the breadth of independent analysis Argon2 has. Argon2id is the strongest overall configuration currently standardized, which is why the direction of travel for new systems is unambiguous.
Why memory hardness actually wins
The history of password cracking is a race between scheme and hardware. MD5 and SHA-256 are CPU-bound: a modern GPU evaluates billions per second because the computation fits in registers and leaks nothing to shared memory. bcrypt raised the CPU cost enormously, but the load is still just CPU cycles — an expensive FPGA or ASIC can pack many bcrypt cores on a die and restore most of the lost throughput.
Argon2 changes the game by requiring memory. A single Argon2id hash at 64 MiB must write and then read roughly 64 MiB × t of RAM. On a GPU, RAM is off-die and bandwidth is the shared bottleneck for every core in a cracking rig; an attacker amortizing thousands of concurrent guesses across one card soon finds the bus saturated. The classic escape hatch — the time-memory tradeoff, computing the hash with less memory in exchange for more compute — is exactly what data-dependent addressing in Argon2d and the hybrid Argon2id is designed to frustrate. Making guesses expensive in RAM is what turned password databases from "crackable overnight" into "crackable only with extraordinary budgets".
Memory hardness does carry one operational cost: a flood of login attempts consumes genuine
RAM per request, so a misconfigured high m can itself enable a denial-of-service
attack at the application layer. That tradeoff is the reason OWASP's floor is deliberately
moderate — 19 MiB is enough to hurt crackers while remaining cheap enough that a busy login
path cannot exhaust a normal server's memory.
How the AnyHash Argon2id tool works
- WebAssembly, not a reimplementation. The hash is computed with
hash-wasm, a versioned WebAssembly build of the Argon2 reference implementation. Results match any other conforming library — Python'sargon2-cffi, Node'sargon2, or the reference CLI — bit for bit. - A Web Worker keeps the page alive. Secure parameters take hundreds of milliseconds to a second and tens of MiB of memory. Instead of freezing the main thread, the derivation runs in a dedicated Worker, so you can keep typing, scroll, and read the guide while the hash computes.
- Cryptographically random salt. The salt field is prefilled with 16 random
bytes (32 hex characters) from
crypto.getRandomValues. The Random button regenerates it; a fresh salt for every hash is what makes identical passwords produce unrelated outputs. - Encoded or raw output. Encoded mode returns the self-describing
$argon2id$…string that production systems store; hex mode returns the raw tag for applications that manage salt and parameters themselves. - Nothing leaves your device. There is no network call in the hashing path — the page, the Worker, and the WASM module are all loaded from the site itself, and the password never appears in a form submission.
Reading an Argon2id hash string
An encoded Argon2id hash is a single string with five segments separated by
$. Take this example for the password correct horse battery staple
at the OWASP-recommended settings:
$argon2id$v=19$m=65536,t=3,p=4$c2FsdHNhbHRzYWx0c2FsdA$qEAsQ6mHvtP/…tag… argon2id— the algorithm identifier (argon2d, argon2i, or argon2id)v=19— the version number (0x13); version 19 is the current standard after a bug fix in early multi-lane implementationsm=65536,t=3,p=4— memory in KiB, iterations, and parallelismc2FsdHNhbHRzYWx0c2FsdA— the salt, Base64-encoded without padding- the final segment — the derived tag, Base64-encoded without padding
Try it: paste the example into this page's verify tab with the password above. Because the string records everything needed — salt, version, and parameters — verification needs no external metadata. Any compliant verifier, on any platform, will re-derive the same tag.
Verification, deep dive
The verify tab performs exactly the operation a production login flow performs:
argon2Verify(password, hash) from the same WebAssembly module. The module parses
the encoded string, reads the salt and parameters, re-runs Argon2id at exactly those
settings, derives the tag, and compares it against the stored tag. The comparison is done in
constant time, so a local check leaks no byte-by-byte information about the tag.
This is also why upgrading parameters is safe: verification always runs at the parameters
written inside the hash, not at whatever the server is configured to use today. When
you decide to raise m from 19 MiB to 64 MiB, old hashes still verify
correctly, and at their original lower cost. This is precisely why the upgrade pattern is
“rehash the password on the next successful login” rather than “reset every password”.
Benchmark before you ship
A good configuration is the highest one your real login path can bear. This page reports the wall-clock time for every hash — use it to calibrate before committing a parameter set to production:
- Run a hash at the OWASP floor (19 MiB, t=2, p=1) and at the recommended 64 MiB, t=3, p=4. Note the difference on this device.
- Decide how much of your peak concurrent login load the server must serve — memory multiplies: 1,000 concurrent logins at 64 MiB is a 64 GiB working set.
- Pick the highest configuration where worst-case verification stays within your SLO — OWASP suggests aiming for at least a quarter of a second on ordinary hardware, and few sites benefit from going beyond roughly a second.
- Re-benchmark annually and after hardware changes; raising parameters later is safe because the cost is embedded in each hash.
Because the browser and the server both run the reference algorithm, a timing measured here closely approximates a native implementation on the same CPU — a reasonable, if not perfect, proxy for what your production server will see.
Migrating from bcrypt to Argon2id
bcrypt remains a solid legacy choice (see our bcrypt guide), but every new system should default to Argon2id. If you already store bcrypt hashes, use the compare-and-upgrade pattern: verify as you do today, and only when the password matches, derive an Argon2id hash at your new parameters and store it beside the old one. Each user migrates on their next successful login, with no forced resets and no readable-plaintext moment. New accounts and password changes should be hashed with Argon2id from day one.
The main reasons a team stays on bcrypt are library availability in an ancient stack and a conservative change control culture — both legitimate, both increasing in friction with every year. Modern frameworks (Laravel, Django, ASP.NET Core, and most runtimes) now ship Argon2id natively or one dependency away. Bench the parameters here, run the upgrade in a canary slice, and let the embedded self-describing format carry the old hashes forward while the new ones take over.