langleyfoxall/laravel-nist-password-rules
Laravel validation rules implementing NIST SP 800-63B password guidance: enforce minimum length, reject breached and common dictionary passwords, block context-specific words, and avoid outdated composition rules. Easy to add to form requests and validators.
langleyfoxall/laravel-nist-password-rules is a Laravel validation-rule package that enforces NIST SP 800-63B password guidance: minimum length (8) and maximum length (64), rejection of common/breached passwords (via the HaveIBeenPwned Pwned Passwords range API using k-anonymity), and rejection of context-specific strings (name, email, username), repeated characters, and keyboard/alphabetic sequences.
Architecture fit. It is a pure validation layer — no migrations, no persistence, no service provider side effects beyond config and translation loading. It plugs into Laravel's Validator through a facade of rule sets (NISTPasswordRules::register(), ::changePassword($username, $email), etc.) and therefore composes with FormRequests, Password::defaults(), Fortify, Breeze, and Jetstream password flows. That means near-zero architectural coupling and no schema or data-model impact. The one non-trivial architectural property is that validation performs a synchronous outbound HTTPS call to api.pwnedpasswords.com on the request path for registration and password-reset submissions.
Integration feasibility. Low. composer require langleyfoxall/laravel-nist-password-rules, optional vendor:publish for the config and lang files, then swap existing min:8|confirmed|regex:... chains for a single rule set in the two or three controllers that touch credentials. Realistic effort for a mid-level Laravel developer is well under a day, including message copy and translations. No infrastructure change is required unless we choose to self-host the breach corpus.
Technical risk.
Key questions for the maintainer/engineering spike.
Http::fake) so our CI does not depend on a live third-party API?Stack fit. Native Laravel — the package targets the framework's Validator contract and ships a facade, config, and lang files. It is framework-idiomatic rather than a bolt-on, so it fits wherever we already use FormRequests or Password::defaults(). It is not appropriate for non-Laravel PHP services in our estate; those would need a direct HIBP range-check client instead.
Migration path. Treat this as a policy migration, not a code migration:
^8.2 in composer.json and publish config/lang files so defaults are reviewable in-repo.Compatibility. Requires a Laravel version within the package's constraint and a PHP version matching its floor; verify against our oldest maintained application before adopting broadly. Password hashing (bcrypt/argon) is unaffected — the 64-character cap is a validation policy, not a storage limit, but confirm no legacy path truncates at 60/72 bytes. Unicode passwords need the app's connection charset to be utf8mb4; where it is not, enforce the cap conservatively to avoid silent truncation.
Sequencing. Pilot (1 app, shadow) → enforce on new-credentials flows (registration, reset, change) → policy and documentation update → second wave of applications → evaluate self-hosted Pwned Passwords if call volume or egress policy demands it. Do not couple this to a framework major-version upgrade; land it as an isolated change so failures are attributable.
Maintenance. Small, slow-moving codebase with a single primary maintainer; the v8.2.0 dependency bump is typical of its cadence — infrequent but alive. Ongoing work is limited to tracking Laravel major releases and refreshing the pinned constraint. Recommended mitigation: fork-and-pin discipline (internal mirror or composer.lock pinning) so an upstream abandonment does not block a framework upgrade, plus a calendar reminder each Laravel release cycle to check compatibility.
Support. The user-visible change is large even though the code change is small: support staff will field "why was my password rejected?" and "why can't I use my usual symbol-heavy password?" Volume should be low but sentiment can be poor if copy is unclear. Rejection messages must be specific ("this password has appeared in a known data breach", "this password is too long") and localised. Publish an internal FAQ before rollout; the dominant ticket driver is confusion over removed complexity requirements, not defects.
Scaling. Validation is synchronous and adds one outbound HTTP round-trip per credential submission — negligible against overall authentication volume for typical apps, but it does put a third party on the critical path of a conversion-sensitive flow. Two levers: cache HIBP range responses (the range → suffix list is stable and cacheable for hours/days) to cut call volume substantially, and configure short timeouts with explicit fail-open/fail-closed behaviour. At high volume or under strict egress controls, self-hosting the Pwned Passwords dataset removes the dependency at the cost of a sizeable on-disk corpus and a periodic refresh job.
Failure modes.
api.pwnedpasswords.com → deterministic validation failures that look like product bugs; add the host to the outbound allowlist and to the dependency register.Ramp-up. Roughly half a day for a Laravel developer familiar with validation to integrate and test, plus one to two days of TPM/compliance time for the policy rewrite and stakeholder sign-off — which is the larger and more schedule-sensitive component. Security, legal/privacy (egress and data-protection review), and support enablement each need a light-touch review; none should gate the technical work, but all should complete before enforcement goes live.
How can I help you explore Laravel packages today?