Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sentinel Unique Passwords Laravel Package

cartalyst/sentinel-unique-passwords

A Cartalyst Sentinel extension that enforces unique passwords by tracking password history and blocking reuse of previous passwords. Hooks into Sentinel's user repository to validate passwords during registration and updates.

View on GitHub
Deep Wiki
Context7

Getting Started

Install alongside Sentinel. This package is an add-on, not a standalone library — it assumes cartalyst/sentinel is already installed and bound in the container. Add it with Composer and let Laravel's package discovery register the service provider:

composer require cartalyst/sentinel-unique-passwords

If discovery is not supported (common for older Cartalyst packages), register the provider manually in config/app.php after Sentinel's own provider.

Look at three things first, in this order:

  1. vendor/cartalyst/sentinel-unique-passwords/composer.json — this is the single most useful file. Confirm the php constraint and the illuminate/* constraint actually overlap with your app's versions. A 2020-era package declaring PHP 8 support may still cap framework versions below what you run.
  2. The package's ServiceProvider — find what it binds or extends. The integration point will almost certainly be Sentinel's hasher (the class implementing Cartalyst\Sentinel\Hashing\HasherInterface), either decoratig the default NativeHasher/BcryptHasher or replacing the binding in the container.
  3. Your Sentinel config (config/cartalyst.sentinel.php) — check whether there is a hasher/driver entry you need to repoint.

First use case. The minimal acceptance test is two accounts, one password:

Sentinel::register(['email' => '[email protected]', 'password' => 'shared-secret']);
Sentinel::register(['email' => '[email protected]', 'password' => 'shared-secret']); // should fail

If the second call throws (or returns a validation failure, depending on how the package surfaces it), the wiring is correct. Do this before touching the password-reset flow, so you have an isolated signal.

Implementation Patterns

Centralize the write path. Every password mutation goes through Sentinel — Sentinel::register(), $user->password = ...; $user->save(), Sentinel::update($user, [...]), and the reminder/reset flow. Do not let application code set a password hash directly on the model; that bypasses the add-on entirely. If you have an admin "create user" or "reset password" UI, route it through Sentinel's repository methods, or explicitly through the hasher, so the uniqueness check runs.

Decorate rather than replace. If you need to extend behaviour, wrap the package's hasher in your own class and extend the check — for example, allowing the current user's password to be re-set to the same value (see below), or logging rejected attempts — rather than editing vendor code. Bind your decorator in a small service provider.

Test fixture strategy. This is where the package bites hardest. Any factory, seeder, or test that creates multiple users with a fixed password ('password', 'secret') will now fail on the second user. Adopt, as a convention:

// database/factories/UserFactory.php
'password' => bcrypt(Str::random(16)), // or Faker's unique password provider

For seeders that need a known dev password, either seed one account or disable the check in local/testing via config if the package exposes a toggle. If it does not, guard the seeder with a per-user suffix ('password-'.$i) and document why.

Handle the failure like a validation error, not a 500. Catch the package's exception at the form-request or controller boundary and re-render with a field-level message. Users should see "Please choose a different password", not a stack trace. Put the mapping in one place — a Handler entry or a PasswordUniquenessException → 422 translation — so registration, profile edit, and password reset all behave identically.

Password reset flow. The reset confirmation endpoint is the easiest place to forget: it sets password via Sentinel and should be covered by the same handler. Add an integration test that resets user B's password to user A's current password and asserts rejection.

Migration/backfill awareness. The check is enforced at set time. Any pre-existing duplicate passwords in the database stay duplicates. If the control matters to you (e.g., a compliance story), you need a one-off audit job that groups by plaintext — which is only possible if you capture it at write time (see gotchas) — or accept that the package only governs new passwords, and document that scope.

Gotchas and Tips

The O(n) hashing problem is the real cost. Salted hashes are not comparable, so detecting a duplicate means verifying the candidate plaintext against every stored hash. Each check is a full bcrypt/argon verification (tens to hundreds of milliseconds). At 10k users, a single registration could take minutes. Mitigate by: checking only on registration and password change (never on every login-adjacent path); scoping the check by a cheap prefilter if the package supports it; or maintaining an HMAC-SHA256 "password fingerprint" column (keyed by an app secret) that you can index and compare in O(1). Verify empirically what the package actually does before you scale past a few thousand rows — the 0-star/0-dependent status means there is no field report to lean on.

Re-setting the same password as yourself. Changing your password to your current password may be flagged as a duplicate of your own account. That is either the intended "don't reuse" behaviour or an annoying false positive; decide which, and if the latter, wrap the hasher to exclude the acting user's user_id from the scan.

Existing duplicates and re-hashing. If Sentinel hashes on model save even when the password did not change, an unrelated profile update could throw. Confirm the hasher is only invoked when the password attribute is dirty; if not, guard the update.

Error message leaking. "This password is already in use" confirms that some account has that password. For a shared-tenant or high-privacy app this is a minor information leak. Consider the generic phrasing above, and rate-limit the endpoint regardless — it is otherwise an oracle for password enumeration.

No documentation, thin maintenance. Last release was December 2020 (a PHP 8 support bump), zero stars, and the license field reads NOASSERTION — resolve that before adopting in commercial code. Practical stance: pin an exact version (5.1.0, not ^5.1), and if the functionality is critical, read the package's hasher class (it will be small) and be prepared to vendor or reimplement it locally. You can reproduce the core behaviour in a decorator around Sentinel's hasher in well under a hundred lines.

Debugging checklist when a duplicate slips through:

  • Dump get_class(app(HasherInterface::class)) — is the package's hasher actually bound, or did your own provider override it later?
  • Confirm the save path goes through Sentinel, not $user->update(['password' => bcrypt(...)]).
  • Check for queue/console context: a CLI seeder may boot a different config or provider set than the HTTP app.
  • Log the rejected attempt (email + timestamp, never the password) at debug level while integrating, then turn it off.

Extension points to lean on. The HasherInterface binding is the natural seam. Anything you want to change — scoping the scan, excluding the current user, skipping in testing, adding metrics — belongs in a decorator bound via your own provider, keeping the vendor directory pristine and the upgrade path to whatever comes next one composer update away.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib