
September 10, 2026
11 min read
By Kokil Thapa | Last reviewed: September 2026
Choosing between bcrypt vs Argon2 vs scrypt for passwords is not an academic exercise. A weak or misconfigured hash is how client portals, eCommerce accounts, and API credentials get cracked after a database leak. On production Laravel and PHP systems I maintain, password hashing sits at the base of every auth stack. This guide compares the three algorithms on real criteria: memory hardness, library support, tuning knobs, and what you can ship today on PHP 8.5 and Laravel 13. For a deeper Argon2id focus, see our Argon2id vs bcrypt comparison for 2026.
Which password hashing algorithm should you choose in 2026?
Start with threat model, not hype. Offline attackers with stolen hashes want cheap parallel guessing. Online attackers hammer your login endpoint. Your algorithm must make offline cracking expensive while staying fast enough for real users.
Argon2id wins for most greenfield work in 2026. It won the Password Hashing Competition and is the current recommendation from OWASP and major language runtimes. bcrypt remains a safe legacy choice with decades of battle testing. scrypt adds memory hardness like Argon2 but sees less first-class support in PHP and Laravel today.
On legal-tech portals and client dashboards I have shipped, auth is only as strong as the slowest part of the stack. Pair a modern hash with rate limiting, as covered in our API rate limiting guide. Strong hashing alone does not stop online guessing.
| Criterion | bcrypt | Argon2id | scrypt |
|---|---|---|---|
| Memory hardness | Low (4 KB state) | High (configurable MiB) | High (configurable) |
| GPU resistance | Good | Excellent | Excellent |
| Side-channel resistance | Moderate | Strong (Argon2id hybrid) | Moderate |
| PHP 8.5 native support | Yes (PASSWORD_BCRYPT) | Yes (PASSWORD_ARGON2ID) | No built-in constant |
| Laravel 13 default | Legacy apps | Recommended | Via custom driver |
| Tuning parameters | Cost factor only | Memory, time, threads | N, r, p, memory |
| 2026 recommendation | Legacy / compat | Default choice | Niche / Node stacks |
Verdict: Argon2id for new work. bcrypt when you must interoperate with old hashes. scrypt when your runtime already standardises on it, such as some Node.js crypto workflows.
How does bcrypt work for password storage?
bcrypt is a password-based key derivation function built on Blowfish. It applies a keyed expansion loop controlled by a cost factor. Each increment doubles the work. That slow loop is the entire point.
Every bcrypt hash embeds its own salt and cost. A typical string looks like $2y$12$.... The prefix tells verifiers which variant and cost to use. You never store the salt separately.
bcrypt in PHP 8.5
<?php
$hash = password_hash('user-secret', PASSWORD_BCRYPT, ['cost' => 12]);
if (password_verify('user-secret', $hash)) {
if (password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 12])) {
$hash = password_hash('user-secret', PASSWORD_BCRYPT, ['cost' => 12]);
}
}
Cost 12 is a common 2026 baseline on a modern VPS. Target roughly 250–500 ms per hash on production hardware. Measure on your server, not your laptop. Shared hosting in Nepal often runs slower CPUs, so cost 10–11 may be the practical ceiling.
bcrypt strengths and limits
- Strengths: Ubiquitous support, simple API, self-describing output, proven track record since the late 1990s.
- Limits: Fixed 72-byte password input cap, low memory use that GPUs exploit, no thread parallelism inside a single hash.
- Common mistake: Pre-hashing with SHA-256 to bypass the 72-byte limit. That turns your hash into a custom scheme and can weaken security if done wrong.
For enterprise application development, bcrypt is acceptable when compliance docs mandate it or when third-party auth libraries only emit bcrypt strings. Plan a rehash path before you paint yourself into a corner.
What makes Argon2 different from bcrypt and scrypt?
Argon2 is a memory-hard function designed to defeat ASIC and GPU farms. Unlike bcrypt, it allocates a large memory block per hash. Attackers cannot scale guesses cheaply by adding more cores alone.
Three variants exist: Argon2d (data-dependent, faster but side-channel risky), Argon2i (data-independent, weaker against offline cracking), and Argon2id (hybrid). Use Argon2id for password storage. It balances GPU resistance with side-channel protection.
Argon2id in PHP 8.5
<?php
$hash = password_hash('user-secret', PASSWORD_ARGON2ID, [
'memory_cost' => 65536, /* 64 MiB */
'time_cost' => 4,
'threads' => 1,
]);
password_verify('user-secret', $hash);
PHP exposes memory in KiB, time as iterations, and threads for parallel lanes. The official PHP password_hash documentation lists defaults per algorithm. Tune until hashing takes a few hundred milliseconds on your production box.
Argon2id in Laravel 13
Laravel 13 ships with Argon2id-friendly defaults in config/hashing.php. Set the driver and options explicitly rather than relying on forgotten framework defaults from an older install.
/* config/hashing.php */
'argon' => [
'memory' => 65536,
'threads' => 1,
'time' => 4,
],
Our Laravel password rehashing and Argon2id setup guide walks through upgrading bcrypt users without forced password resets. That pattern matters on long-lived portals like Mijar Law Associates, where accounts may sit untouched for months.
When should you use scrypt instead of Argon2 or bcrypt?
scrypt was designed in 2009 to make hardware cracking expensive through memory and CPU cost. Parameters N (CPU/memory cost), r (block size), and p (parallelism) control the work factor. It predates Argon2 and influenced its design.
In PHP, scrypt is not a first-class password_hash() constant. You would pull in libsodium or a vetted Composer package. That extra dependency is why most PHP teams skip scrypt today when Argon2id is already native.
Where scrypt still appears
- Node.js crypto:
crypto.scrypt()is built in. Node.js 26 LTS projects sometimes standardise on scrypt for internal tools. - Crypto wallets and blockchain-adjacent apps: Historical scrypt usage in key derivation, not always interchangeable with web password storage.
- Cross-language parity: When a mobile app and API already share scrypt parameters, changing algorithms requires coordinated releases.
On a greenfield API development project, I would pick Argon2id unless a spec explicitly requires scrypt. The OWASP Password Storage Cheat Sheet lists Argon2id as the preferred option when available.
How do you tune cost parameters without locking out users?
Parameter tuning is ops work, not a one-time dev task. Hashes that take two seconds on a cheap VPS will timeout under load during traffic spikes. Hashes that take 50 ms are too cheap for offline defence.
Practical targets
- bcrypt: Cost 12 on a 2026 cloud VPS; drop to 10–11 on constrained shared hosting.
- Argon2id: 64 MiB memory, time cost 3–4, one thread per hash on web requests.
- scrypt: Follow RFC 7914 guidance; match memory to available RAM on the app server.
Run a micro-benchmark on production hardware after deploy. I've seen Laravel apps behave differently on Linux VPS hosting versus local Docker because CPU pinning and opcache state differ. Re-test after any hosting migration.
Never benchmark only registration. Login peaks matter more. A Dashain sale on an eCommerce site can multiply concurrent verifications. Pair tuning with queue-based registration if you expect bursts.
What never belongs in your stack
MD5, SHA-1, and unsalted SHA-256 are not password hashes. They are fast digests. An attacker can test billions per second on a single GPU. If you inherit legacy digests, force a reset or rehash at next login with a proper algorithm.
Use our password generator tool for test credentials during QA. Production passwords should come from users or a vetted manager, not predictable dev strings checked into Git.
How do you migrate from bcrypt to Argon2id safely?
Migration is a login-time upgrade, not a batch rewrite of plaintext. You do not have plaintext for existing users unless you stored it, which would be a separate disaster.
The standard pattern uses password_needs_rehash() in PHP or Laravel's Hash::needsRehash(). After a successful verify against the old bcrypt string, rehash with Argon2id and save.
/* Laravel controller excerpt */
if (Hash::check($request->password, $user->password)) {
if (Hash::needsRehash($user->password)) {
$user->forceFill([
'password' => Hash::make($request->password),
])->save();
}
}
Store only the hash string in the database. A column width of 255 characters covers all three algorithms. Do not truncate Argon2 output.
On client portals with document uploads, auth upgrades should sit inside your regular support and maintenance cycle. Schedule the config change, deploy, and monitor login latency for a week.
For WordPress 7.1 sites, core still centres on bcrypt-style phpass hashes. Custom plugins can wrap Argon2, but test plugin compatibility first. Our WordPress development service usually recommends a custom auth layer or SSO rather than patching core hashing ad hoc.
WooCommerce 11.1 inherits WordPress user tables. Treat shop customer passwords with the same upgrade discipline as your admin accounts. Checkout guest flows do not remove the need for strong hashing on registered buyers.
How does bcrypt vs Argon2 vs scrypt fit Laravel Passport, Sanctum, and API auth?
Token-based API auth does not replace password hashing. Sanctum and Passport still persist user passwords for the token issuance login step. Weak hashes undermine the entire API surface.
Read our Laravel Passport vs Sanctum comparison for auth architecture. Regardless of token type, the password column should use Argon2id in 2026.
On Quick And Easy Nepalese Grocery, customer accounts and admin APIs share one user table. One hashing policy covers web login and mobile-friendly token auth. Split policies create audit gaps.
Secrets for API keys belong in environment variables or encrypted vaults, not user password columns. See Ansible Vault for secrets for infrastructure-side handling. Application password hashing and deployment secret storage solve different problems.
Rate limit login and token endpoints. Hash strength buys time after a leak; rate limits reduce live guessing. Test under load as part of testing and optimization before launch.
Key Takeaways
- Choose Argon2id for new PHP 8.5 and Laravel 13 applications; it beats bcrypt and scrypt on memory hardness and side-channel resistance.
- Keep bcrypt only for legacy databases and migrate with verify-then-rehash on login, not bulk SQL updates.
- Target 250–500 ms per hash on production hardware; measure on the server that actually runs PHP-FPM.
- Never use MD5, SHA-1, or raw SHA-256 for passwords; use
password_hash()or LaravelHashfacades only. - Pair strong hashing with rate limiting, HTTPS, and breach-ready logging on every auth endpoint.
- scrypt is valid in Node.js 26 stacks but rarely worth extra PHP dependencies when Argon2id is native.
People Also Ask
Is bcrypt still secure in 2026?
Yes, bcrypt is still secure when configured with an adequate cost factor and a unique salt per password. It is no longer the best default because Argon2id offers stronger memory hardness. Existing bcrypt hashes remain safe to verify while you rehash on login.
Why do developers prefer Argon2id over Argon2i or Argon2d?
Argon2id combines data-independent and data-dependent passes. That hybrid resists both side-channel timing leaks and GPU offline cracking better than either pure variant. OWASP and PHP both treat Argon2id as the password-storage variant.
Can I use scrypt and Argon2 in the same database?
Yes. Stored hash strings are self-describing. Your verify function checks the prefix and runs the matching algorithm. After verify, rehash everything to a single target algorithm so future code stays simple.
What hash does Laravel 13 use by default?
Laravel 13 supports bcrypt and Argon2 drivers via the hashing config. New projects should set the Argon2 driver with tuned memory and time costs. Laravel 12 also supports Argon2 when PHP 8.2 or higher includes the extension.
Ship the right hash before your next auth feature
The bcrypt vs Argon2 vs scrypt for passwords debate has a practical answer for 2026: Argon2id first, bcrypt for legacy verify-and-upgrade, scrypt only when your stack already depends on it. Pick parameters on production metal, wire rehashing into login, and stop treating password columns as an afterthought.
If you are launching a portal, API, or eCommerce auth layer and want hashing, rate limits, and deployment reviewed together, contact us or explore custom software development. Read more on the blog, review portfolio projects with live auth, or learn about our work on the about page.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

