infinitypaul/laravel-password-history-validation
Laravel validation rule that stops users from reusing old passwords. It stores password history, checks new passwords against previous hashes, and offers configurable limits so you can drop it into any form request or validator with minimal setup.
Architecture fit: infinitypaul/laravel-password-history-validation is a single-purpose Laravel validation package that enforces password history/reuse policies (e.g. "cannot reuse last N passwords") via a custom validation rule and a supporting table. This is a narrow, well-bounded concern that fits cleanly into the Laravel validator pipeline and is typically wired into Password::defaults(), FormRequests, or a registration/reset controller. It is framework-coupled by design (service provider, migration, validation rule contract), which is fine in a Laravel-first stack but means it is not portable to non-Laravel PHP services or to frontend-only policy enforcement.
Integration feasibility: High for the stated scope. The 2.0.2 release materially improves integration ergonomics in two ways:
users tables (common in Laravel apps using HasUuids/ULIDs or distributed ID strategies). Previously this was a likely blocker for any application not on auto-increment integer user IDs.database/migrations path, which is the standard Enterprise/SaaS pattern for schema governance, custom indexing, and multi-tenant shard-per-database deployments. This removes the previous requirement to run migrations from the package's opaque load path and reduces "hidden schema" risk in change review.Everything else in the release (PR #17 StyleCI) is cosmetic and carries no functional risk.
Technical risk: Low-to-moderate. Key considerations:
Hash::check against prior hashes). If the algorithm or HASH_DRIVER changes, old rows may become unverifiable — this needs explicit documentation in your runbook.Key questions for the maintainer/team:
user_id foreign keys in both the published and package-managed migration paths, and is the column type configurable?config file publishable and versioned, and is a retention/pruning command provided?Stack fit: Requires Laravel (service provider + validation rule + migration). Confirm the app's Laravel major is inside the package's supported range — the 2.x line should be checked against the framework version pinned in composer.json before adoption. Not suitable for shared validation logic across non-Laravel services; if password policy must be enforced in more than one runtime, this package becomes one implementation among several and policy drift is a real risk.
Migration path:
^2.0.2 and review the 2.0.1→2.0.2 diff; it is additive (UUID support, publishable migrations) plus style fixes, so no code changes are expected from 2.0.1.user_id column type matches the local users table (uuid vs foreignId), or the foreign key will fail at migrate time on strict drivers.Compatibility: The UUID change widens the addressable table; confirm it does not silently assume a column name or type that conflicts with existing tenant-scoped schemas. Multi-tenant databases (per-tenant migrations) need the published migration replicated across every tenant shard — plan the rollout job accordingly.
Sequencing:
(user_id, created_at)).Password::defaults() / FormRequests behind a feature flag.Maintenance: Low ongoing effort but non-zero ownership. Three things must live in the app repo, not the package: the published migration, the retention/pruning job, and the hasher-compatibility runbook. The package's contributor base is thin — budget for the possibility of vendoring a fork if the upstream goes quiet; the code surface is small enough that this is cheap insurance.
Support: Expect two classes of tickets: (a) "I can't reuse my password" confusion at enforcement time, and (b) edge cases where a user's pre-adoption password history is empty and the rule appears not to fire. Both are product/UX issues rather than defects, and both are solvable with clear copy and a documented soft-launch period.
Scaling: The validation check is a single indexed lookup on user_id at password-change time — a low-frequency, low-contention path. No meaningful scaling concern on read. The only scaling risk is table growth: unbounded history rows across a large user base. Ship a retention policy (keep last N, or age-based purge) at launch rather than retrofitting it. For tenant-sharded deployments, the migration must be applied per shard and the rollout tracked as a fleet operation, not a single deploy.
Failure modes:
user_id column type not aligned with the users table (especially post-UUID-support) → migration failure or silent non-enforcement. Mitigate with staging validation across both key types.HASH_DRIVER or rehashing invalidates historical comparisons; old hashes must remain verifiable.Ramp-up: Low. A Laravel developer can integrate in well under a day: install, publish, migrate, attach the rule. The real ramp-up cost is organizational, not technical — agreeing the policy parameters (history depth, retention window, which surfaces enforce it), sequencing the rollout behind a flag, and getting comms and support ready for the first cohort of blocked users. Estimate: ~1 developer-day for engineering, plus a product/security review cycle to sign off on depth and retention.
How can I help you explore Laravel packages today?