Under the Hood

Password Hashing - bcrypt() vs Hash::make() Deep Dive

Learn the difference between bcrypt() and Hash::make() in Laravel 12. Understand password hashing algorithms, security levels, performance, and when to use each method.

Muhammad Waqas

Muhammad Waqas

CEO at CentoSquare

|
12-Dec-2025
6 min read
Password Hashing - bcrypt() vs Hash::make() Deep Dive

When securing user passwords in Laravel, you have two seemingly identical options: bcrypt() and Hash::make(). Both create hashed passwords, but are they really the same? Let's dive deep into Laravel's password hashing mechanisms and uncover the critical differences that impact your application's security.

The Quick Answer

Both bcrypt() and Hash::make() can hash passwords, but they're not identical:

// Using bcrypt() helper
$hashed = bcrypt('secret123');

// Using Hash facade
$hashed = Hash::make('secret123');

The key difference: bcrypt() always uses bcrypt algorithm, while Hash::make() uses your configured default algorithm (bcrypt or Argon2).

What Is Password Hashing?

Password hashing is a one-way cryptographic function that transforms a plain-text password into a fixed-length string. The critical property: you cannot reverse it to get the original password.

$password = 'secret123';
$hashed = bcrypt($password);

// Result: $2y$12$rFh3Z.8xK5L6N4Q9P7M2XeYp...
// You CANNOT reverse this to get 'secret123'

This is different from encryption, which can be reversed with a key. Hashing is intentionally irreversible.

The bcrypt() Helper Function

The bcrypt() helper is a convenience function that specifically uses the bcrypt algorithm:

$hashed = bcrypt('password123');

Behind the scenes, it's a shortcut that calls Hash::make() with bcrypt:

// What bcrypt() actually does internally
function bcrypt($value, $options = []) {
    return app('hash')->driver('bcrypt')->make($value, $options);
}

Bcrypt Algorithm Characteristics

Bcrypt has been the industry standard for password hashing since 1999:

  • Cost Factor: Configurable computational cost (default: 12 rounds)
  • Salt: Automatically generates unique salts for each password
  • Output Length: Fixed 60-character string
  • Speed: Intentionally slow (100-300ms) to prevent brute force
// Bcrypt output format
$2y$12$rFh3Z.8xK5L6N4Q9P7M2XeYp1Q2W3E4R5T6Y7U8I9O0P1A2S3D4F5
│││ │  │                                                      │
││└─ Cost factor (2^12 = 4096 rounds)                        └─ Hash (31 chars)
│└── Bcrypt algorithm version                                   
└─── Salt (22 characters)

The Hash::make() Facade Method

Hash::make() is Laravel's main password hashing interface:

use Illuminate\Support\Facades\Hash;

$hashed = Hash::make('password123');

Unlike bcrypt(), it respects your configuration and can use multiple algorithms.

Configuration in config/hashing.php

return [
    'driver' => 'bcrypt', // or 'argon2id', 'argon2i', 'argon'
    
    'bcrypt' => [
        'rounds' => env('BCRYPT_ROUNDS', 12),
    ],
    
    'argon' => [
        'memory' => 65536, // KB
        'threads' => 1,
        'time' => 4,       // Iterations
    ],
];

When you call Hash::make(), it uses the driver specified in this config.

Bcrypt vs Argon2: The Real Difference

Bcrypt (Default)

// config/hashing.php
'driver' => 'bcrypt',

// Usage
$hashed = Hash::make('password'); // Uses bcrypt
$hashed = bcrypt('password');     // Always uses bcrypt

Pros:

  • Proven track record (25+ years)
  • Widely supported across platforms
  • Lower memory usage
  • Predictable performance

Cons:

  • Limited to 72 character passwords
  • Single-threaded (can't utilize multiple CPU cores)
  • Fixed memory usage

Argon2 (Modern Alternative)

// config/hashing.php
'driver' => 'argon2id', // Most secure variant

// Usage
$hashed = Hash::make('password'); // Uses Argon2
$hashed = bcrypt('password');     // Still uses bcrypt!

Pros:

  • Winner of Password Hashing Competition (2015)
  • Configurable memory, time, and parallelism
  • Resistant to GPU/ASIC attacks
  • Supports unlimited password length

Cons:

  • Higher memory usage (65 MB default)
  • Requires PHP 7.2+ with Argon2 support
  • Less mature than bcrypt

When to Use Each Method

Use bcrypt() When:

// 1. You explicitly want bcrypt regardless of config
$hashed = bcrypt($password);

// 2. Quick prototyping or simple applications
User::create([
    'email' => $request->email,
    'password' => bcrypt($request->password),
]);

// 3. You're certain you'll always use bcrypt

Use Hash::make() When:

// 1. You want configuration flexibility
$hashed = Hash::make($password);

// 2. Building production applications
User::create([
    'email' => $request->email,
    'password' => Hash::make($request->password),
]);

// 3. You might switch algorithms in the future

// 4. You need custom hashing options
$hashed = Hash::make($password, [
    'rounds' => 14, // More secure but slower
]);

Password Verification

Both methods produce hashes that can be verified using Hash::check():

// Hash with either method
$hashed = bcrypt('secret123');
// OR
$hashed = Hash::make('secret123');

// Verify with Hash::check()
if (Hash::check('secret123', $hashed)) {
    // Password is correct
}

Laravel automatically detects the algorithm used and verifies accordingly:

// Behind the scenes in Hash::check()
if (starts_with($hashed, '$2y$')) {
    // Use bcrypt verification
} elseif (starts_with($hashed, '$argon2')) {
    // Use Argon2 verification
}

Rehashing Passwords

Laravel can automatically upgrade password hashes when algorithms change:

// During authentication
if (Hash::needsRehash($user->password)) {
    $user->password = Hash::make($plainPassword);
    $user->save();
}

This is useful when:

  • Upgrading from bcrypt to Argon2
  • Increasing bcrypt rounds for better security
  • Migrating from old hashing methods

Example workflow:

public function login(Request $request)
{
    if (Auth::attempt($request->only('email', 'password'))) {
        $user = Auth::user();
        
        // Check if password needs rehashing
        if (Hash::needsRehash($user->password)) {
            $user->password = Hash::make($request->password);
            $user->save();
        }
        
        return redirect()->intended('dashboard');
    }
}

Performance Comparison

// Bcrypt with 12 rounds
$start = microtime(true);
bcrypt('password123');
$bcryptTime = microtime(true) - $start;
// Average: 150-250ms

// Argon2id with default settings
$start = microtime(true);
Hash::make('password123'); // With driver = 'argon2id'
$argonTime = microtime(true) - $start;
// Average: 200-400ms

Argon2 is intentionally slower with higher memory usage to resist specialized hardware attacks.

Custom Hashing Options

Both methods accept options for fine-tuning:

// Bcrypt with custom rounds
$hashed = bcrypt('password', ['rounds' => 14]);
// OR
$hashed = Hash::make('password', ['rounds' => 14]);

// Argon2 with custom settings
$hashed = Hash::driver('argon2id')->make('password', [
    'memory' => 131072, // 128 MB
    'time' => 6,
    'threads' => 2,
]);

Higher values mean more security but slower hashing. Balance based on your server capabilities and user patience.

Common Mistakes to Avoid

Mistake 1: Double hashing

// WRONG - hashing an already hashed password
$hashed = bcrypt($request->password);
$doubleHashed = bcrypt($hashed); // Don't do this!

// CORRECT - hash once
$hashed = bcrypt($request->password);

Mistake 2: Using md5 or sha1

// NEVER DO THIS - these are cryptographic hashes, not password hashes
$insecure = md5($password);     // Fast, no salt, broken
$insecure = sha1($password);    // Fast, no salt, weak

// ALWAYS use proper password hashing
$secure = Hash::make($password);

Mistake 3: Comparing hashed passwords directly

// WRONG - timing attack vulnerable
if ($hashed === $inputHashed) {
    // Login
}

// CORRECT - use Hash::check()
if (Hash::check($input, $hashed)) {
    // Login
}

Security Best Practices

  1. Never store plain-text passwords - Always hash before storing
  2. Use proper verification - Always use Hash::check(), never direct comparison
  3. Consider Argon2 - For new applications, Argon2id offers better security
  4. Increase cost over time - As hardware improves, increase rounds/memory
  5. Implement rehashing - Automatically upgrade old hashes during login

Conclusion

Both bcrypt() and Hash::make() secure your passwords effectively, but Hash::make() offers more flexibility and future-proofing. For production applications, prefer Hash::make() to leverage configuration options and easy algorithm switching.

The choice between bcrypt and Argon2 depends on your requirements: bcrypt for proven reliability and broad support, Argon2 for maximum security against modern attacks. Either way, Laravel handles the complexity so you can focus on building features.


Need help securing your Laravel application or upgrading legacy authentication systems? At NeedLaravelSite, we specialize in Laravel security best practices and application migrations from version 7 to 12. We ensure your user data is protected with modern password hashing and authentication systems.


Article Tags

Laravel password hashing bcrypt vs Hash make Laravel bcrypt Laravel Hash facade Laravel authentication security

About the Author

Muhammad Waqas

Muhammad Waqas

CEO at CentoSquare

Founder & CEO at CentoSquare | Creator of NeedLaravelSite | Helping Businesses Grow with Cutting-Edge Web, Mobile & Marketing Solutions | Building Innovative Products