Hashing is a one-way process that turns a password (or any data) into a fixed-length scrambled string. Unlike encryption, you cannot reverse a hash β you can only check if a given value matches the hash. This is exactly what you want for passwords: store the hash, and verify against it on login.
Why Hash Passwords?
// NEVER store passwords in plain text!
$user->password = 'secret123'; // Anyone with DB access can read it
$user->save();// Hash the password β it becomes unreadable
$user->password = Hash::make('secret123');
$user->save();
// Stored as: "$2y$12$K4Iu6q7cW8e..." (nobody can read the original)If your database is ever compromised, hackers get useless hash strings instead of real passwords.
1. Bcrypt (Default)
Laravel uses Bcrypt by default. It's slow on purpose β this makes brute-force attacks impractical.
use Illuminate\Support\Facades\Hash;
// Create a hash
$hashed = Hash::make('my-password');
// Result: "$2y$12$K4Iu6q7cW8e..."
// Each call produces a DIFFERENT hash (due to random salt)
Hash::make('my-password'); // "$2y$12$abc..."
Hash::make('my-password'); // "$2y$12$xyz..."
// Both are valid hashes of the same password!
// Verify a password against a hash
if (Hash::check('my-password', $hashed)) {
// Password is correct!
}
if (! Hash::check('wrong-password', $hashed)) {
// Password is wrong
}2. Configuring Bcrypt Rounds
"Rounds" control how slow hashing is. More rounds = more secure but slower. Default is 12.
'bcrypt' => [
'rounds' => env('BCRYPT_ROUNDS', 12), // Default: 12
],// Override rounds for a specific hash
$hashed = Hash::make('password', [
'rounds' => 14, // Slower but more secure
]);| Rounds | Speed | Use case |
|---|---|---|
| 10 | ~65ms | Testing / development |
| 12 | ~250ms | Default β good balance |
| 14 | ~1s | High security applications |
3. Argon2 (Alternative)
Argon2 is a newer algorithm that won the Password Hashing Competition. It's more resistant to GPU-based attacks.
// Switch to Argon2
'driver' => 'argon2id', // or 'argon2i'
'argon' => [
'memory' => 65536, // Memory cost in KiB (64MB)
'threads' => 1, // Number of threads
'time' => 4, // Number of iterations
],// The API stays the same regardless of driver
$hashed = Hash::make('password'); // Uses Argon2 if configured
Hash::check('password', $hashed); // Works the same way4. Auto-Rehashing
If you change your hashing configuration (e.g., increase rounds), old hashes still work. Laravel can automatically rehash on login:
use Illuminate\Support\Facades\Hash;
// Check if a hash needs to be rehashed (config changed)
if (Hash::needsRehash($user->password)) {
$user->update([
'password' => Hash::make($plainPassword),
]);
}public function login(Request $request)
{
$credentials = $request->validate([
'email' => 'required|email',
'password' => 'required',
]);
if (Auth::attempt($credentials)) {
// Auto-rehash if config changed
if (Hash::needsRehash(Auth::user()->password)) {
Auth::user()->update([
'password' => Hash::make($request->password),
]);
}
return redirect('/dashboard');
}
return back()->withErrors(['email' => 'Invalid credentials']);
}5. Common Patterns
User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);public function changePassword(Request $request)
{
$request->validate([
'current_password' => 'required',
'new_password' => 'required|min:8|confirmed',
]);
// Verify current password
if (! Hash::check($request->current_password, auth()->user()->password)) {
return back()->withErrors(['current_password' => 'Current password is incorrect']);
}
// Update with new hash
auth()->user()->update([
'password' => Hash::make($request->new_password),
]);
return back()->with('success', 'Password changed!');
}// app/Models/User.php
use Illuminate\Database\Eloquent\Casts\Attribute;
protected function password(): Attribute
{
return Attribute::make(
set: fn (string $value) => Hash::make($value),
);
}
// Now you can just do:
$user->password = 'plain-text'; // Auto-hashed before saving!Summary
- βOne-way β hashes cannot be reversed (unlike encryption)
- βHash::make() β create a hash from a password
- βHash::check() β verify a password matches a hash
- βBcrypt β default, 12 rounds, good for most apps
- βArgon2 β alternative, more resistant to GPU attacks
- βneedsRehash() β auto-upgrade hashes when config changes