guilhermednt/pathwell-bundle
A Symfony bundle that brings PathWell password-policy validation to your app, detecting keyboard-walk patterns and weak password topologies. Enforce stronger credentials with configurable rules and straightforward integration.
This is a thin Symfony bundle (single release, June 2022) that wraps a PathWell topology check: it maps each character of a password to a class (lower, upper, digit, symbol), builds a topology string like ULLLLLDD, and rejects passwords whose topology is in a configured list of common/weak topologies. It is a policy validator, not an entropy or breach checker.
composer require guilhermednt/pathwell-bundle
If Flex has no recipe, add it manually to config/bundles.php (Guilhermednt\PathWellBundle\PathWellBundle::class => ['all' => true], verify the exact namespace in vendor/.../src/).src/DependencyInjection/Configuration.php (the real config tree — the README is sparse), src/Validator/ (the constraint + validator pair you'll actually use), and src/Resources/config/ (service tags, especially validator.constraint_validator).config/packages/pathwell.yaml enabling the check and pointing at a topology list. The list is the policy — a bundle with an empty or default list does nothing useful, so budget time for sourcing data (see below).plainPassword field, never on the entity's hashed password property:
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'constraints' => [
new Length(['min' => 12]),
new PathWell(), // FQCN from src/Validator/
new NotCompromisedPassword(),
],
])
bin/console debug:validator App\Entity\User (or your DTO) and bin/console lint:container; a silently unregistered validator tag means every password passes.Apply it at the boundary, not on the entity. Passwords arrive as plaintext on forms, API payloads, and console commands; they leave as hashes. Use a DTO (RegistrationInput, ChangePasswordInput) or form-level constraints so the rule is reusable across web, API, and admin paths without fighting Doctrine lifecycle callbacks.
Cover all three entry points consistently: self-registration, password change, and password reset. A policy enforced only on registration is trivially bypassed via "change password". Admin "invite/create user" flows are the usual hole.
Compose, don't substitute. PathWell rejects predictable shapes (Password1! passes a length check but fails topology). Pair it with Length/PasswordStrength and NotCompromisedPassword. Order matters: cheap checks first so users get the most actionable error.
Treat the topology list as configuration with a lifecycle. Source it from the published PathWell topology corpus or generate it from your own password corpus; store it as a versioned file in config/ and load it via the bundle's config key rather than inlining thousands of entries into YAML. Review it periodically — the ranked list drifts as attacker dictionaries evolve.
Per-environment tuning: strict in prod, and either strict-but-fixed or disabled in test so fixture passwords stay deterministic. Don't disable it in dev if you want developers to hit the same UX you ship.
Legacy users: apply the policy on change, not on login; never lock out existing accounts because their old hash can't be re-validated.
Custom error messaging. Topology rejections are confusing ("your password pattern is too common"). Override the constraint's message and provide a translation, or users will assume the form is broken. Point them at the fix: "use a less predictable mix of words, numbers, and symbols."
Test at two levels. A unit test building the validator via Validation::createValidatorBuilder()->enableAnnotationMapping()-style bootstrap for the constraint itself, plus one functional form test asserting a known-bad topology (Password1) fails and a good one passes. This also catches upstream breakage on Symfony upgrades.
composer.json. For many teams the honest conclusion is "reimplement the 50-line topology check in-house" — it's a character-class map plus a hash-set lookup, and you avoid the licence and abandonment risk entirely.symfony/framework-bundle below 6.4/7.x and may emit deprecations on PHP 8.2+. Run composer why-not symfony/framework-bundle ^7.0 and a full test suite before adopting; forks are likely.aaaaaaaaaaaa and qwertyuiop12 can survive a topology check. Always combine with length and a breach list._, whitespace, and non-ASCII letters; use multibyte-safe splitting (mb_str_split) so accented characters don't corrupt the topology string. Uppercase detection for non-Latin scripts is unreliable — consider treating them as a single class.cache:clear time. Load it in a service from a resource file, cached in memory per request.bin/console debug:container --tag=validator.constraint_validator confirms registration; debug:validator shows constraints per class. If validations appear to be ignored, it is almost always a missing service tag or a constraint applied to the wrong property.How can I help you explore Laravel packages today?