PHP
bcrypt
password hashing
web development
security

How do you use bcrypt for hashing passwords in PHP?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In PHP, the correct way to use bcrypt is through the password API, not by building salts or calling cryptographic functions manually. The main workflow is simple: hash new passwords with password_hash(), verify logins with password_verify(), and rehash later if your cost settings change.

Hashing a Password with Bcrypt

PHP exposes bcrypt through PASSWORD_BCRYPT:

php
1<?php
2$password = 'CorrectHorseBatteryStaple';
3
4$hash = password_hash($password, PASSWORD_BCRYPT, [
5    'cost' => 12,
6]);
7
8if ($hash === false) {
9    throw new RuntimeException('Hashing failed');
10}
11
12echo $hash . PHP_EOL;

The generated string already contains the algorithm marker, salt, and cost information. You do not need to create or store a separate salt column.

Verifying Passwords on Login

When a user logs in, compare the submitted password to the stored hash with password_verify():

php
1<?php
2$enteredPassword = 'CorrectHorseBatteryStaple';
3$storedHash = '$2y$12$exampleexampleexampleexampleexampleexampleexampleexample';
4
5if (password_verify($enteredPassword, $storedHash)) {
6    echo 'Password is valid';
7} else {
8    echo 'Invalid password';
9}

In a real application, storedHash comes from your database row for that user. password_verify() handles the salt and cost embedded in the stored hash, which is why manual salt management is unnecessary.

Rehashing When Your Settings Change

As hardware improves, you may want a higher cost. PHP gives you password_needs_rehash() so you can upgrade stored hashes gradually during login:

php
1<?php
2$password = 'CorrectHorseBatteryStaple';
3$storedHash = getHashFromDatabase();
4
5if (password_verify($password, $storedHash)) {
6    if (password_needs_rehash($storedHash, PASSWORD_BCRYPT, ['cost' => 12])) {
7        $newHash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
8        saveNewHashForUser($newHash);
9    }
10
11    echo 'Login success';
12}
13
14function getHashFromDatabase(): string {
15    return password_hash('CorrectHorseBatteryStaple', PASSWORD_BCRYPT, ['cost' => 10]);
16}
17
18function saveNewHashForUser(string $hash): void {
19    echo 'Hash upgraded' . PHP_EOL;
20}

This lets you strengthen password storage without forcing every user to reset a password immediately.

Choosing a Cost Value

The bcrypt cost controls how much work the hash requires. A higher cost is stronger but slower. The right value depends on your hardware and acceptable login latency.

A simple benchmark script helps you choose a reasonable number:

php
1<?php
2$password = 'benchmark-password';
3
4for ($cost = 10; $cost <= 13; $cost++) {
5    $start = microtime(true);
6    password_hash($password, PASSWORD_BCRYPT, ['cost' => $cost]);
7    $elapsed = microtime(true) - $start;
8
9    echo "cost={$cost} time={$elapsed}" . PHP_EOL;
10}

Pick a cost that is slow enough to resist brute-force attempts but still acceptable for login traffic in your application.

Storing the Hash Correctly

Store the full hash string exactly as returned by password_hash(). Do not truncate it, split it apart, or base64-encode it again.

A typical schema uses a text column large enough to hold the full password hash. The application should never store the original password, even temporarily beyond the point required to hash it.

Why the Password API Matters

PHP’s password API protects you from several common mistakes:

  • manual salt generation
  • incorrect comparison logic
  • outdated hashing patterns such as raw SHA-256 for passwords
  • accidental omission of future rehash support

That is why the modern answer is not “call bcrypt directly,” but “use PHP’s password helpers with bcrypt.”

Common Pitfalls

The worst mistake is hashing passwords with general-purpose functions such as md5(), sha1(), or a plain hash() call. Those are fast, which is exactly what you do not want for password storage.

Another pitfall is trying to verify passwords by hashing the login input again and comparing strings. With proper password hashing, you should always use password_verify().

Developers also sometimes choose a cost value blindly. If it is too low, security suffers. If it is too high, logins become unnecessarily slow under load.

Finally, do not confuse hashing with encryption. Passwords should usually be hashed one-way, not encrypted for later recovery.

Summary

  • In PHP, use password_hash() with PASSWORD_BCRYPT to create bcrypt password hashes.
  • Use password_verify() to check login attempts against stored hashes.
  • Let PHP manage salt handling instead of building that logic yourself.
  • Use password_needs_rehash() to upgrade cost settings over time.
  • Store the full returned hash and never use fast general-purpose hash functions for passwords.

Course illustration
Course illustration

All Rights Reserved.