jblab/password-validator-bundle
jblab/password-validator-bundle adds configurable password validation to PHP apps, letting you enforce length, complexity, and common-password rules through a simple validator constraint for safer user credentials.
This is a Symfony bundle, not a Laravel package — there is no service provider, no config/password-validator.php to publish, and no auto-discovery. Treat 2.1.0 as a maintenance release: it only widens the Symfony constraint to include ^8.0. Nothing else changed, so upgrading from 2.0.3 is a drop-in with no code edits.
Where to look first:
composer require jblab/password-validator-bundle — but read the composer.json requirement block before committing. If it pulls symfony/framework-bundle, you are installing a chunk of the Symfony framework into a Laravel app just to validate a password.Constraint object you can hand to Laravel's validator.First use case: a registration or password-reset FormRequest that rejects weak passwords before they reach your User model.
// app/Rules/PasswordStrength.php
class PasswordStrength implements ValidationRule
{
public function validate(string $attribute, mixed $value, Closure $fail): void
{
$constraint = new PasswordStrengthConstraint([/* options from README */]);
$violations = (new PasswordStrengthValidator())->validate($value, $constraint);
if (count($violations) > 0) {
$fail($violations[0]->getMessage());
}
}
}
Then 'password' => ['required', 'confirmed', new PasswordStrength()] in the form request.
Wrap, don't register. The bundle expects a Symfony kernel to boot its extension. In Laravel, instantiate the constraint and validator directly (as above) or bind a configured instance in a service provider so options live in one place:
$this->app->singleton(PasswordStrengthConstraint::class, fn () => new PasswordStrengthConstraint(
config('auth.password_strength')
));
Layer it with Laravel's own rules. This package answers "is this password complex enough?" — it does not replace Password::defaults(), which handles the compromised-password check and gives you Password::min(12)->uncompromised()->mixedCase()->numbers()->symbols(). The pragmatic split is: use Laravel's Password rule for the baseline, and bring this package in only when you need rule sets Laravel doesn't express (custom scoring, per-tenant policies, message localisation from the validator's violation objects).
Profile per surface. Registration, password reset, and admin-created accounts usually warrant different thresholds. Keep profiles in config/auth.php or a dedicated config file and select by guard or route:
'password_strength' => [
'default' => ['min_length' => 12, /* ... */],
'admin' => ['min_length' => 16, /* ... */],
],
Surface violations properly. The validator returns violation objects, not Laravel MessageBag entries. Map them into your $fail() calls (one rule per violation, or a single aggregated message) so assertSessionHasErrors and API error payloads stay consistent with the rest of your app.
Test at the rule boundary. Because you own the wrapper, unit-test the Rule with data providers rather than testing the vendor class — that keeps your suite green across future upstream releases.
Symfony 8 support is probably a no-op for you. Laravel 11/12 pin Symfony components at 6.x/7.x. Unless something in your tree pulls symfony/* to 8.x, Composer will resolve the same versions it did on 2.0.3. The feature matters if you run this bundle inside a Symfony 8 app or a Laravel project that deliberately floats Symfony 8 components — otherwise it is a version-constraint widening with zero behavioural impact.
Do not assume the bundle boots. There is no bundle.php equivalent in Laravel, no PasswordValidatorBundle::class entry in bootstrap/providers.php that does anything. Anything the bundle's README tells you to configure under config/packages/ must be translated into a plain PHP config array you pass to the constraint constructor yourself.
Watch the dependency weight. A Symfony bundle typically requires symfony/framework-bundle, symfony/dependency-injection, and friends. If composer require wants to add half the framework, stop and check whether a standalone validator package from the same vendor satisfies the requirement instead.
Messages and translation. Symfony constraints route violation messages through the Symfony translator, which is not wired up in Laravel. Expect raw English message strings unless you supply your own. Publish/override them by mapping violation codes to lang/en/validation.php keys, or just author your messages in the wrapper.
Debugging checklist when a password you expect to pass is rejected:
dd($constraint) — confirm the options array actually received your config (a singleton bound before config is cached is a common cause of stale values).$fail calls — an empty errors() bag with a failing test usually means you returned early in the wrapper.Extension points are limited by design. There is no Laravel-side hook for custom scoring rules in this package; if you need a bespoke policy (dictionary checks, tenant-specific blocklists), implement it as a second Laravel rule composed alongside this one rather than trying to subclass the validator. Keep the vendor class as a leaf dependency so future major versions are cheap to adopt.
Pin sensibly. "jblab/password-validator-bundle": "^2.1" is safe given the release is additive. Re-evaluate only if a future major bumps the minimum PHP or drops a Symfony major, since that ripples into your platform requirements.
How can I help you explore Laravel packages today?