Password
The Password component provides secure password hashing and verification. It wraps PHP's password_* functions with a type-safe Algorithm enum and a clean functional API, making it easy to hash passwords with bcrypt or Argon2 and handle algorithm upgrades over time.
Hashing a Password
use Psl\IO;
use Psl\Password;
$plaintext = 'my-secret-password';
// Uses the default algorithm (currently bcrypt, may change in future PHP versions)
$hash = Password\hash($plaintext);
IO\write_line('Default hash: %s', $hash);
// Specify an algorithm explicitly
$bcryptHash = Password\hash($plaintext, Password\Algorithm::Bcrypt);
IO\write_line('Bcrypt hash: %s', $bcryptHash);
You can tune algorithm parameters through the $options array:
use Psl\IO;
use Psl\Password;
$plaintext = 'my-secret-password';
// Bcrypt with a higher cost factor (default is 10)
$hash = Password\hash($plaintext, Password\Algorithm::Bcrypt, ['cost' => 14]);
IO\write_line('Bcrypt (cost 14): %s', $hash);
Verifying a Password
verify() checks a plaintext password against a stored hash. The algorithm and salt are embedded in the hash itself, so you do not need to store them separately:
use Psl\IO;
use Psl\Password;
$plaintext = 'my-secret-password';
$storedHash = Password\hash($plaintext, Password\Algorithm::Bcrypt);
if (Password\verify($plaintext, $storedHash)) {
IO\write_line('Password is correct.');
} else {
IO\write_line('Password is incorrect.');
}
Checking If a Rehash Is Needed
When you upgrade your hashing algorithm or increase the cost factor, existing hashes remain valid but are no longer up to your current standard. needs_rehash() detects this so you can transparently upgrade hashes at login time:
use Psl\IO;
use Psl\Password;
$plaintext = 'my-secret-password';
$storedHash = Password\hash($plaintext, Password\Algorithm::Bcrypt);
if (Password\verify($plaintext, $storedHash)) {
IO\write_line('Password is correct.');
// Check if the hash needs upgrading
if (Password\needs_rehash($storedHash, Password\Algorithm::Bcrypt, ['cost' => 14])) {
$newHash = Password\hash($plaintext, Password\Algorithm::Bcrypt, ['cost' => 14]);
IO\write_line('Hash upgraded: %s', $newHash);
// store $newHash in the database
} else {
IO\write_line('Hash is up to date.');
}
}
This pattern lets you migrate from bcrypt to Argon2id (or increase cost parameters) gradually, without forcing all users to reset their passwords.
Inspecting a Hash
get_information() returns the algorithm and options used to create a hash:
use Psl\IO;
use Psl\Password;
$hash = Password\hash('my-secret-password', Password\Algorithm::Bcrypt);
$info = Password\get_information($hash);
IO\write_line('Algorithm: %s', $info['algorithm']->name);
IO\write_line('Cost: %d', $info['options']['cost'] ?? '<unknown>');
Algorithm
The Password\Algorithm enum provides four cases:
Default-- follows PHP's default, which may change over time to adopt stronger algorithmsBcrypt-- Blowfish-based, always produces 60-character hashesArgon2i-- memory-hard algorithm resistant to GPU attacksArgon2id-- hybrid of Argon2i and Argon2d, recommended for most applications
When using Algorithm::Default, store hashes in a column that can hold at least 255 characters, since the underlying algorithm (and hash length) may change in future PHP versions.
See src/Psl/Password/ for the full API.