Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Password Hasher Laravel Package

symfony/password-hasher

Symfony PasswordHasher provides secure password hashing and verification with modern algorithms like bcrypt and sodium. Use PasswordHasherFactory to configure multiple hashers and select the right one for your app’s needs.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation:

    composer require symfony/password-hasher
    

    Laravel users can skip this if using Laravel 8+ (included by default).

  2. Basic Configuration (Laravel): Update config/auth.php or config/app.php to leverage the package:

    'hashers' => [
        'default' => [
            'algorithm' => 'bcrypt',
            'cost' => 12, // Adjust based on performance/security tradeoffs
        ],
        'admin' => [
            'algorithm' => 'argon2id',
            'memory_cost' => 65536,
            'time_cost' => 4,
            'threads' => 2,
        ],
    ],
    
  3. First Use Case: Hashing a Password Replace Hash::make() with the Symfony hasher in your User model or registration logic:

    use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
    
    // In a service or controller
    $passwordHasher = app(UserPasswordHasherInterface::class);
    $hash = $passwordHasher->hashUserPassword($user, 'plain-text-password');
    
  4. Verification:

    if ($passwordHasher->isPasswordValid($user, 'submitted-password')) {
        // Password is correct
    }
    
  5. Legacy Migration (if needed): Use the rehash() method to upgrade old hashes:

    $passwordHasher->rehashUserPassword($user, 'plain-text-password');
    

Where to Look First


Implementation Patterns

Core Workflows

1. Algorithm-Specific Hashing

Use the PasswordHasherFactory to dynamically select algorithms:

$factory = new PasswordHasherFactory([
    'bcrypt' => ['algorithm' => 'bcrypt', 'cost' => 14],
    'argon' => ['algorithm' => 'argon2id', 'memory_cost' => 128 * 1024],
]);

$bcryptHasher = $factory->getPasswordHasher('bcrypt');
$argonHasher = $factory->getPasswordHasher('argon');

2. Role-Based Hashing

Assign algorithms per user role (e.g., admins get Argon2id):

// In User model
public function getPasswordHasherName(): string
{
    return $this->isAdmin() ? 'argon' : 'bcrypt';
}

3. Laravel Service Provider Integration

Bind the factory to the container in AppServiceProvider:

public function register()
{
    $this->app->singleton(PasswordHasherFactory::class, function ($app) {
        return new PasswordHasherFactory([
            'default' => ['algorithm' => 'bcrypt', 'cost' => 12],
        ]);
    });
}

4. Auto-Rehashing on Login

Rehash legacy passwords during authentication:

public function attemptLogin(Request $request)
{
    $user = User::where('email', $request->email)->first();
    if ($user && $this->passwordHasher->isPasswordValid($user, $request->password)) {
        $this->passwordHasher->rehashUserPassword($user, $request->password);
        // Proceed with login
    }
}

5. Custom Hashers

Extend PasswordHasherInterface for bespoke algorithms:

class CustomHasher implements PasswordHasherInterface
{
    public function hash(string $plainPassword): string { /* ... */ }
    public function verify(string $hashedPassword, string $plainPassword): bool { /* ... */ }
}

Register it in the factory:

$factory = new PasswordHasherFactory([
    'custom' => new CustomHasher(),
]);

Integration Tips

Laravel-Specific

  • Replace Hash Facade: Use UserPasswordHasherInterface directly for granular control.
  • Password Reset: Extend Illuminate\Auth\Passwords\PasswordBrokerManager to use Symfony’s hasher.
  • Testing: Mock UserPasswordHasherInterface in unit tests:
    $hasher = $this->createMock(UserPasswordHasherInterface::class);
    $hasher->method('hashUserPassword')->willReturn('$2y$10$hashed');
    $this->app->instance(UserPasswordHasherInterface::class, $hasher);
    

Performance Optimization

  • Benchmark Algorithms: Use symfony/security:hash-password CLI tool to test latency:
    php bin/console security:hash-password
    
  • Cache Hashers: Singleton the PasswordHasherFactory to avoid recreating hashers.

Migration Strategies

  • Phased Rollout: Start with bcrypt, then introduce Argon2id for high-risk users.
  • Database Backfill: Use Laravel queues to rehash passwords in batches:
    User::chunk(100, function ($users) {
        foreach ($users as $user) {
            $this->passwordHasher->rehashUserPassword($user, $user->password);
        }
    });
    

Gotchas and Tips

Pitfalls

  1. Algorithm Mismatch Errors:

    • Symptom: InvalidArgumentException when verifying hashes.
    • Cause: Hashing with one algorithm (e.g., bcrypt) and verifying with another (e.g., Argon2id).
    • Fix: Ensure consistent algorithm usage via getPasswordHasherName() or factory configuration.
  2. Argon2id Resource Usage:

    • Symptom: Slow login times or timeouts.
    • Cause: High memory_cost or time_cost values.
    • Fix: Start with conservative values (e.g., memory_cost: 64MB, time_cost: 3) and benchmark.
  3. Legacy Hash Detection:

    • Symptom: RuntimeException for unsupported hash formats (e.g., MD5).
    • Fix: Use PasswordHasherFactory::supports() to check compatibility:
      if (!$factory->supports($user->password)) {
          $user->password = $factory->getPasswordHasher('bcrypt')->hash($user->password);
      }
      
  4. Laravel Caching Conflicts:

    • Symptom: Cached users fail verification after password changes.
    • Fix: Clear cache or use Auth::logoutOtherDevices() post-update.
  5. PHP Extensions:

    • Symptom: ClassNotFoundException for Sodium or Argon2.
    • Fix: Enable extensions in php.ini:
      extension=sodium
      extension=php_argon2
      

Debugging Tips

  • Verify Hashes Manually:
    php artisan tinker
    >>> $hasher = app(Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface::class);
    >>> $hasher->isPasswordValid($user, 'test-password') // true/false
    
  • Check Algorithm Support:
    $factory->getSupportedAlgorithms(); // ['bcrypt', 'argon2id', 'sodium']
    
  • Log Hashing Events:
    $hasher->hashUserPassword($user, $password)
        ->then(function ($hash) { Log::debug("Password hashed for user {$user->id}"); });
    

Configuration Quirks

  1. Default Algorithm:

    • If unset, Symfony defaults to bcrypt. Explicitly define it to avoid surprises:
      'hashers' => [
          'default' => ['algorithm' => 'bcrypt'], // Force bcrypt
      ]
      
  2. Sodium Fallback:

    • Sodium (for sodium algorithm) may not be available on all hosts. Test with:
      if (!class_exists(Sodium::class)) {
          throw new RuntimeException('Sodium extension required for sodium algorithm.');
      }
      
  3. Laravel Hash Facade:

    • Avoid mixing Hash::make() and Symfony’s hasher. Stick to one for consistency.

Extension Points

  1. Custom Password Hasher: Implement PasswordHasherInterface for proprietary algorithms (e.g., GPU-accelerated hashing).

  2. Event Listeners: Trigger events for hash operations:

    event(new PasswordHashed($user, $hash));
    event(new PasswordVerified($user, $result
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata