jord-jd/password_exposed
Laravel package to block compromised passwords using the Have I Been Pwned Pwned Passwords API. Adds easy validation rules and checks during registration or password changes, helping prevent users from choosing exposed credentials.
Installation
composer require jord-jd/password_exposed
Add the service provider to config/app.php:
'providers' => [
// ...
JordJd\PasswordExposed\PasswordExposedServiceProvider::class,
],
Configuration Publish the config file:
php artisan vendor:publish --provider="JordJd\PasswordExposed\PasswordExposedServiceProvider"
Update config/password_exposed.php with your Have I Been Pwned (HIBP) API key (free tier available).
First Use Case Check if a password is exposed in a registration or login flow:
use JordJd\PasswordExposed\Facades\PasswordExposed;
$isExposed = PasswordExposed::check('password123');
if ($isExposed) {
return back()->withErrors(['password' => 'This password has been exposed in a data breach.']);
}
Registration Validation Integrate with Laravel’s validation pipeline:
use Illuminate\Support\Facades\Validator;
$validator = Validator::make($request->all(), [
'password' => [
'required',
'string',
'min:8',
'confirmed',
'password_exposed', // Custom rule
],
]);
Register the rule in AppServiceProvider@boot():
Validator::extend('password_exposed', function ($attribute, $value, $parameters) {
return !PasswordExposed::check($value);
});
Password Reset Flow Check exposed passwords before resetting:
public function update(Request $request) {
$request->validate([
'password' => ['required', 'password_exposed'],
]);
// Reset logic...
}
Bulk Checks (Admin Panel)
Use the checkMultiple() method for batch validation (e.g., user imports):
$exposedPasswords = PasswordExposed::checkMultiple([
'password1', 'password2', 'password3'
]);
// Returns associative array: ['password1' => true/false, ...]
Rate Limiting Cache results to avoid API abuse (e.g., 5-minute cache):
$isExposed = Cache::remember("password_exposed_{$password}", now()->addMinutes(5), function() use ($password) {
return PasswordExposed::check($password);
});
resources/lang/en/validation.php:
'password_exposed' => 'The :attribute has been exposed in a data breach.',
if ($isExposed) {
\Log::warning("Exposed password detected: {$request->password}");
}
PasswordExposed::setFallbackList(['password', '123456']);
API Rate Limits
False Positives
qwerty) may trigger unnecessarily.'whitelist' => ['correcthorsebatterystaple'],
Performance
Privacy Compliance
PasswordExposed::setDebug(true); // Logs API responses to storage/logs/password_exposed.log
PasswordExposed::setMockResponse(true); // Returns hardcoded results
Custom Data Sources
Extend the JordJd\PasswordExposed\Contracts\PasswordExposedContract to integrate with other breach databases (e.g., DeHashed):
class CustomPasswordExposed implements PasswordExposedContract {
public function check(string $password): bool {
// Custom logic...
}
}
Bind it in AppServiceProvider:
$this->app->bind(PasswordExposedContract::class, CustomPasswordExposed::class);
Event Listeners Trigger actions when exposed passwords are detected:
PasswordExposed::addListener(function ($password, $isExposed) {
if ($isExposed) {
event(new ExposedPasswordDetected($password));
}
});
Configuration Overrides Dynamically adjust sensitivity (e.g., disable checks for admins):
if (auth()->user()->isAdmin()) {
PasswordExposed::setEnabled(false);
}
How can I help you explore Laravel packages today?