laravel-password maintained by groupesti
Laravel Password
Password policy and lifecycle for Laravel: a validation rule that extends
Illuminate\Validation\Rules\Password, blocklists (file + database), password
reuse prevention, expiration / forced change, breach detection (HaveIBeenPwned)
and user/administrator notifications — fully configurable and translated.
Installation
composer require groupesti/groupesti-password
php artisan vendor:publish --tag=password-config
php artisan migrate
For the lifecycle columns on the users table:
php artisan vendor:publish --tag=password-migrations
php artisan migrate
The validation rule
use Password\Password;
$request->validate([
'password' => Password::min(12)
->letters(1) // >= 1 letter
->mixedCase(1) // >= 1 uppercase and >= 1 lowercase
->numbers(2) // >= 2 digits
->symbols(1) // >= 1 symbol
->upperCase(1, 3) // min/max bounds per case
->allowSpaces(false)
->maxConsecutive(3) // no more than 3 identical characters in a row
->maxRepeats(4) // a character at most 4 times
->maxSequential(4) // no run (abc / 123) longer than 4
->noKeyboardPatterns() // forbid azerty/qwerty
->notContainsUserInfo() // forbid name/email/username
->notContains() // forbidden-word dictionary
->normalize() // NFKC + reject control characters
->uncompromised() // HaveIBeenPwned
->blocklists(), // internal file + DB blocklists
]);
Every character-class method follows the signature (?int $min = 1, ?int $max = null):
a bare call requires "at least 1", null disables the bound.
Default policy
Password::defaults() builds the rule from config/password.php:
'password' => Password::defaults(),
Utilities
Password::generate(); // random policy-compliant password
Password::strength($password); // ['bits' => 84, 'level' => 'very_strong', 'score' => 4]
Lifecycle (history, expiration, forced change)
On your User model:
use Password\Traits\ManagesPasswordLifecycle;
use Password\Interfaces\PasswordLifecycle;
class User extends Authenticatable implements PasswordLifecycle
{
use ManagesPasswordLifecycle;
}
Prevent reuse (last N or N days, depending on the config):
use Password\Rules\NotReused;
$request->validate([
'password' => [Password::defaults(), NotReused::for($request->user())],
]);
On every password change: $user->markPasswordChanged();
Force a change through the middleware:
Route::middleware(['auth', 'password.require-change'])->group(/* ... */);
Real-time compromise detection + notifications
Enable password.realtime.enabled: on sign-in the password is checked against
HaveIBeenPwned and the configured action is applied (force_change | notify |
block). User and administrator notifications, as well as a scheduled digest
(daily/weekly/monthly), are configured in the notifications section.
Operational errors (an unavailable blocklist source, etc.) throw exceptions that self-report: logging + administrator alert.
Component stubs
Ready-to-use password fields (show/hide toggle, strength meter, live requirements):
php artisan vendor:publish --tag=password-stubs-blade-tailwind
php artisan vendor:publish --tag=password-stubs-blade-bootstrap
php artisan vendor:publish --tag=password-stubs-vue-tailwind
php artisan vendor:publish --tag=password-stubs-vue-bootstrap
Translations
Provided for: en, fr, es, de, pt-BR, it, nl, ru, zh-CN, ja, ar, tr.
php artisan vendor:publish --tag=password-lang
License
MIT. See license.md.