unicodeveloper/laravel-password
Laravel Password is a simple package that stops users from choosing common or weak passwords. It ships with a list of the top 10,000 most-used passwords and adds validation rules so you can block them in registration and password reset forms.
composer require unicodeveloper/laravel-password
Laravel 5.5+ auto-discovers the service provider. On older 5.x apps, add Unicodeveloper\Password\PasswordServiceProvider::class to the providers array in config/app.php, then publish the config so you can see (and extend) the blocklist:
php artisan vendor:publish --provider="Unicodeveloper\Password\PasswordServiceProvider"
First use case is registration. Drop the package's password rule onto your password field alongside the usual constraints:
$request->validate([
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed|password',
]);
Where to look first:
config/password.php (published) — this is the dictionary of "dumb" passwords the rule rejects. Skim it so you know what it actually catches (top-N common passwords, keyboard walks, repeated characters, etc.). It is a static list, not a strength meter.vendor/unicodeveloper/laravel-password/src — confirm exactly how comparison is done (trimming, casing, whether it hashes the input before comparing).php artisan tinker to smoke-test the rule against a handful of inputs before wiring it into a FormRequest.No migrations, no storage, no hashing — the package is pure validation.
FormRequest is the natural home. Keep the rule out of controllers so every entry point uses the same policy:
class RegisterRequest extends FormRequest
{
public function rules(): array
{
return [
'email' => ['required', 'email', 'unique:users'],
'password' => ['required', 'string', 'min:8', 'confirmed', 'password'],
];
}
}
Cover every password-setting path, not just signup. The most common production gap is that registration is protected but these are not:
ResetPasswordController / Fortify / Breeze actions)Stack it, don't substitute it. The rule answers "is this in the dumb list?" — it does not answer "is this strong?" Pair it with length, confirmed, and on Laravel 8.6+ the built-in strength/breach rules:
use Illuminate\Validation\Rules\Password as StrongPassword;
'password' => ['required', 'confirmed', 'password', StrongPassword::min(12)->letters()->numbers()->uncompromised()],
Custom rule object (newer releases). If your pinned version exposes a rule class rather than the string alias, inject it into the rules array instead:
use Unicodeveloper\Password\Rules\Password as DumbPassword;
'password' => ['required', 'min:8', new DumbPassword],
Customise the message. Either override in resources/lang/en/validation.php under the rule's key, or pass a messages array to validate() / FormRequest::messages() so the copy reads like a product message ("That password is too common — pick something less guessable").
Testing. Assert the failure path explicitly so a future Laravel upgrade that silently drops the rule is caught:
$this->post('/register', ['password' => 'password', ...])
->assertSessionHasErrors('password');
$this->post('/register', ['password' => 'correct-horse-battery', ...])
->assertSessionHasNoErrors();
Password rule. From Laravel 8 onward, Illuminate\Validation\Rules\Password exists. If you mix string and object rules, alias your imports (use ... as DumbPassword) — otherwise you'll get confusing "not a valid rule" or type errors.min, confirmed, or uncompromised(). It also won't catch user-specific dumbness ([email protected] → john2024); add a custom check that compares the password against the email/name if that matters to you.'password' throws "validation rule does not exist," check the README for that tag and use the rule object instead. Pin the version in composer.json so this can't shift under you.PassWord or password slipping through is the classic false negative; normalise in your own rule if needed.config/password.php, run php artisan config:clear (or config:cache on deploy) — in cached environments your new banned entries won't apply.password key like any other rule, so JSON clients get a 422 with errors.password. Make sure your SPA maps that key to the field rather than showing a generic "something went wrong."Validator::make(['password' => $pw], ['password' => 'password'])->fails() — before blaming your request pipeline. It's almost always the rule not being loaded (provider missing / config cached) rather than the comparison logic.How can I help you explore Laravel packages today?