← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

password_verify()

php PHP 5.5+ Beginner

Also Known As

password_verify() PHP password check bcrypt verify

TL;DR

Checks a plaintext password against a bcrypt/Argon2 hash produced by password_hash() — the correct way to validate passwords.

Explanation

password_verify($plaintext, $hash) compares a user-supplied password against a stored hash created by password_hash(). It automatically extracts the algorithm, cost, and salt from the stored hash string and is timing-safe. Never compare password hashes with == or === — this is vulnerable to timing attacks and type juggling. password_verify() always returns bool and handles all supported PHP password algorithms transparently.

Common Misconception

password_verify() can be replaced with hash comparison using ===. password_verify() performs a constant-time comparison internally. Using === leaks timing information, and also fails to account for future algorithm upgrades handled automatically by password_needs_rehash().

Why It Matters

password_verify() extracts the algorithm and salt from the stored hash and recomputes it — it is the only correct way to verify a password_hash() result because the salt is embedded.

Common Mistakes

  • Comparing hashes with === instead of password_verify() — the embedded salt means the same password produces different hashes.
  • Not calling password_needs_rehash() after a successful verify — misses the opportunity to upgrade old hashes.
  • Using password_verify() to compare non-password hashes like HMACs — use hash_equals() for those.
  • Assuming password_verify() is timing-safe against all attacks — it is, but only use it for password_hash() outputs.

Code Examples

✗ Vulnerable
// Wrong — hashing again and comparing:
$inputHash = password_hash($input, PASSWORD_BCRYPT);
if ($inputHash === $storedHash) { /* Always false — different salts */ }

// Correct:
if (password_verify($input, $storedHash)) { /* Correct */ }
✓ Fixed
// Constant-time, extracts salt from hash automatically
\$hash  = \$user->password; // from database
\$input = \$_POST['password'];

if (password_verify(\$input, \$hash)) {
    // Authenticated — check if rehash needed
    if (password_needs_rehash(\$hash, PASSWORD_ARGON2ID, ['memory_cost' => 65536])) {
        \$new = password_hash(\$input, PASSWORD_ARGON2ID);
        User::where('id', \$user->id)->update(['password' => \$new]);
    }
} else {
    // Wrong password — use identical code path as 'user not found' to prevent enumeration
    abort(401, 'Invalid credentials');
}

Added 15 Mar 2026
Edited 22 Mar 2026
Views 26
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
2 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 2 pings F 0 pings S
No pings yet today
Amazonbot 1
Amazonbot 10 Perplexity 5 Unknown AI 3 Google 2 Ahrefs 2 Majestic 1
crawler 21 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Low
⚡ Quick Fix
Use password_verify($input, $hash) — it's constant-time and handles the salt embedded in the bcrypt/argon2 hash automatically; never compare hashes with == or ===
📦 Applies To
PHP 5.5+ web api
🔗 Prerequisites
🔍 Detection Hints
Hash comparison with === or ==; md5($password) comparison; SHA1 for password storage; no password_verify() usage
Auto-detectable: ✓ Yes semgrep phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✓ Auto-fixable Fix: Low Context: Line Tests: Update
CWE-916

✓ schema.org compliant