Bcrypt vs Argon2: Choosing a Password Hashing Algorithm

Passwords

Storing passwords in plaintext is the fastest way to lose your users' trust. The industry standard is to hash passwords with a slow, salted algorithm designed specifically for this purpose. The two most common choices today are bcrypt and Argon2.

How Password Hashing Works

Unlike general-purpose hash functions (SHA-256, MD5), password hashing algorithms are intentionally slow. They apply the hash function thousands or millions of times so that brute-forcing a stolen database is computationally expensive.

Both bcrypt and Argon2:

  • Automatically generate a unique salt per password, preventing rainbow-table attacks.
  • Include a cost factor that lets you increase work as hardware gets faster.
  • Produce a self-contained hash string that embeds the salt and parameters.

Bcrypt

Bcrypt has been the default choice since 1999. It's battle-tested, widely supported, and understood.

Key characteristics:

  • Cost parameter: A single "rounds" value (default 12 = 2¹² iterations). Each increment doubles the time.
  • Fixed memory: Bcrypt uses a fixed 4 KB buffer (Eksblowfish state), making it vulnerable to GPU/ASIC attacks that can run many instances in parallel.
  • 72-byte limit: Only the first 72 bytes of the password are hashed. Longer passwords are silently truncated.
  • Output format: $2b$12$... — a 60-character string that encodes version, rounds, salt, and hash.

Hash a password with bcrypt using the Auth Toolkit API:

curl -X POST https://auth.toolkitapi.io/v1/auth/hash-password \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"password": "hunter2", "algorithm": "bcrypt", "rounds": 12}'

Argon2

Argon2 won the Password Hashing Competition in 2015 and is the newer, recommended option. It comes in three variants:

Variant Resists Best for
Argon2d GPU attacks Backend services not exposed to timing attacks
Argon2i Side-channel attacks Login servers where timing matters
Argon2id Both Recommended default — hybrid of d and i

Key characteristics:

  • Memory-hard: You configure how much RAM each hash requires (e.g., 64 MB). This makes GPU/ASIC attacks dramatically more expensive because GPUs have limited per-core memory.
  • Three tuning knobs: memory cost, time cost (iterations), and parallelism (threads).
  • No length limit: The full password is always hashed.
  • Output format: $argon2id$v=19$m=65536,t=3,p=4$... — a self-describing string like bcrypt.
curl -X POST https://auth.toolkitapi.io/v1/auth/hash-password \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"password": "hunter2", "algorithm": "argon2"}'

Head-to-Head Comparison

Feature Bcrypt Argon2id
Year introduced 1999 2015
Memory usage Fixed 4 KB Configurable (e.g., 64 MB)
GPU/ASIC resistance Moderate Strong (memory-hard)
Password length limit 72 bytes None
Tuning parameters Rounds Memory, time, parallelism
Library support Everywhere Most modern languages
OWASP recommendation Acceptable Preferred

Which Should You Choose?

Choose Argon2id if you're starting a new project. It's the OWASP-recommended default and provides stronger resistance against modern hardware attacks. Use at least 64 MB of memory, 3 iterations, and 4 threads.

Bcrypt is still fine for existing systems. With 12+ rounds, it remains secure against remote attacks. If you're already using bcrypt and your hashes are salted, there's no urgent need to migrate — but consider upgrading new hashes to Argon2id over time.

Migrating gradually: You can verify passwords against old bcrypt hashes and re-hash them with Argon2id on the next successful login. The Auth Toolkit's Verify Password endpoint detects the algorithm automatically, and the needs_rehash field tells you when it's time to upgrade.

Verifying Passwords

Regardless of algorithm, always verify using constant-time comparison:

curl -X POST https://auth.toolkitapi.io/v1/auth/verify-password \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"password": "hunter2", "hash": "$2b$12$LJ3m4ys..."}'

The response tells you whether the password matches, which algorithm was detected, and whether the hash should be upgraded:

{
  "valid": true,
  "algorithm_detected": "bcrypt",
  "needs_rehash": false
}

Try it out

Browse Tools →

More from the Blog