Weave 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

Laravel Needs Auto Rehash Laravel Package

samasend/laravel-needs-auto-rehash

Laravel Needs Auto Rehash automatically detects outdated password hashes and rehashes them after successful login, keeping user credentials aligned with your app’s current hashing algorithm and cost settings with minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package:

composer require samasend/laravel-needs-auto-rehash
  • Laravel 5.5+ auto-discovery picks up the service provider — no manual registration.
  • It's zero-config: no php artisan vendor:publish. Behavior follows your existing config/hashing.php (driver, bcrypt.rounds, argon.*).
  • Look first at the package's listener source (src/), specifically which events it hooks (Login, Registered, PasswordReset) and where it reads the plaintext password. The whole package is a few dozen lines; read it before trusting it.
  • First use case: you bumped bcrypt.rounds from 10 → 12, or switched HASH_DRIVER to argon2id. Existing users shouldn't need to reset. After installing, on a user's next successful login their hash is silently upgraded.
  • Verify it worked: log in as a test user, then check the password column — it should now start with $2y$12$ (or $argon2id$) and differ from the old value.

Implementation Patterns

Standard Auth::attempt — the happy path. The listener needs the plaintext password and gets it off the current request (typically request()->input('password')). Any login built on Auth::attempt() where the field is named password works with no code changes: Breeze, Fortify/Jetstream, Laravel UI, your hand-rolled LoginController.

Custom credential field name. If your form posts pass or user_password, Auth::attempt() still succeeds — but the listener can't find the plaintext and silently does nothing. Normalize the field name in your controller, or replace the listener (see Gotchas).

API / token auth. Sanctum, Passport, and HTTP basic auth don't fire Illuminate\Auth\Events\Login, so no rehash happens. Handle it manually where you have the plaintext:

if (Hash::needsRehash($user->password)) {
    $user->update(['password' => Hash::make($request->password)]);
}

Programmatic login. Auth::login($user) fires Login, but there's no password in the request, so the listener skips. Rehash explicitly at points where you hold the plaintext: registration, admin password reset, impersonation flows.

Testing. Don't Event::fake() in tests that assert rehashing — the listener won't run. Assert against the DB instead:

$oldHash = $user->password;
$this->post('/login', ['email' => $user->email, 'password' => 'secret']);
$this->assertNotSame($oldHash, $user->fresh()->password);

To force needsRehash() to return true, set a different bcrypt.rounds in the test environment than the one used by your factory.

Algorithm migration. Set HASH_DRIVER=argon2id, deploy, and let users upgrade on next login. bcrypt hashes keep verifying in the meantime — BcryptHasher still checks old $2y$ hashes even when the default driver is argon. Test this end-to-end in staging before rolling it out.

Gotchas and Tips

  • Archived, last release Feb 2023. No security patches, no guaranteed Laravel 11/12 support. The listener is ~30 lines — fork it into app/Listeners/ and own it rather than depending on an abandoned package.
  • It's request-coupled. The biggest footgun: the plaintext comes from the request, not the event. Any flow without a password field in the request silently does nothing. If "rehash isn't working," dump request()->input('password') in a temporary listener first.
  • Fires after successful auth only. Confirm the listener runs after Illuminate\Auth\Events\Login — not before credential validation. Rehashing on a failed login would be wrong.
  • Sessions are not invalidated by a rehash. The user stays logged in; other active sessions remain valid. If rehashing is part of a security remediation, log out other sessions explicitly.
  • Event ordering matters. If your own Login listeners touch password (audit logging, etc.), check whether they observe the old or new value — registration order determines this.
  • Config cache. Changing bcrypt.rounds or HASH_DRIVER without rebuilding the config cache rehashes with the stale cost, looking like nothing happened. Run php artisan config:cache after changes.
  • Argon2 needs the PHP extension. On hosts without sodium/argon support, needsRehash() is fine but Hash::make() throws at login. Verify the extension in the target environment before flipping the driver.
  • Extension / replacement points. Need a custom field name, extra events, or logging? Don't fight the package — register your own listener in EventServiceProvider::boot(), or uninstall and copy the logic. The package provides no config surface to hook into.
  • Debug loop: temporarily log inside a Login listener — Log::info('login', ['has_plain' => request()->filled('password'), 'needs' => Hash::needsRehash($event->user->password)]). That single line tells you whether the problem is the package or your login flow.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package