divineomega/symfony-password-exposed-bundle
haveibeenpwned.com API interaction via the jord-jd/password_exposed library, providing a clean interface (PasswordExposedCheckerInterface). This aligns well with decoupled architecture principles.HttpClient, Cache, and Config components.HttpClient/Cache systems differ from Symfony’s (e.g., Guzzle vs. Symfony’s HttpClient).haveibeenpwned.com’s passwords API (free tier: 2,000 checks/day). Rate limits and API changes could impact reliability.| Risk Area | Description |
|---|---|
| API Limitations | Free tier of haveibeenpwned.com has rate limits (2,000 checks/day). Enterprise use may require paid plans or caching strategies. |
| Symfony Lock-in | Laravel integration would require adapters for Symfony’s HttpClient, Cache, and Config. |
| Cache Invalidation | Stale cache (default: 30 days) could lead to false negatives if breaches are added to HIBP’s database. |
| Performance Overhead | API calls add latency (~100–300ms per check). Bulk checks (e.g., during user imports) could degrade performance. |
| Maintenance Burden | Dependency on a third-party API introduces external risk (downtime, schema changes). |
| Component | Symfony Fit | Laravel Fit | Mitigation Strategy |
|---|---|---|---|
| HTTP Client | ✅ Native | ❌ (Guzzle) | Use Symfony’s HttpClient in a Laravel service or wrap Guzzle in PSR-18. |
| Cache | ✅ Native | ❌ (Cache) | Adapt Laravel’s Cache facade to Symfony’s CacheInterface or use PSR-6. |
| Config | ✅ Native | ❌ (.env) |
Move config to a Symfony-style YAML/XML or use a config adapter. |
| Dependency Inj. | ✅ Native | ❌ (Container) | Use Symfony’s ContainerBuilder or Laravel’s ServiceProvider for DI. |
composer require jord-jd/symfony-password-exposed-bundle
config/packages/password_exposed.yaml):
password_exposed:
enable: true
cache: cache.app
cache_lifetime: 2592000 # 30 days
PasswordExposedCheckerInterface into controllers/services.use JordJD\PasswordExposed\Interfaces\PasswordExposedCheckerInterface;
public function register(Request $request, PasswordExposedCheckerInterface $checker) {
$password = $request->request->get('password');
if ($checker->isExposed($password)) {
throw new \RuntimeException("Password exposed in a breach!");
}
// Proceed with registration...
}
KernelEvents::REQUEST to auto-check passwords in forms.composer require jord-jd/password_exposed
namespace App\Services;
use JordJD\PasswordExposed\PasswordExposedChecker;
use Psr\Cache\CacheItemPoolInterface;
use Psr\Http\Client\ClientInterface;
class LaravelPasswordExposedChecker
{
public function __construct(
private ClientInterface $httpClient,
private CacheItemPoolInterface $cache
) {}
public function isExposed(string $password): bool {
$checker = new PasswordExposedChecker($this->httpClient, $this->cache);
return $checker->isExposed($password);
}
}
AppServiceProvider):
$this->app->bind(ClientInterface::class, function () {
return new \GuzzleHttp\Client(); // PSR-18 adapter
});
public function register(Request $request, LaravelPasswordExposedChecker $checker) {
if ($checker->isExposed($request->password)) {
return back()->withErrors(['password' => 'Exposed in a breach!']);
}
}
HttpClient or vice versa).Cache → Symfony’s CacheInterface)..env → YAML/XML).jord-jd/password_exposed directly).| Task | Symfony | Laravel |
|---|---|---|
| Updates | composer update + config check |
Manual dependency updates |
| Cache Management | Symfony’s Cache system |
Laravel’s Cache + custom logic |
| Logging | Symfony’s Monolog |
Laravel’s Log facade |
| API Key Rotation | Config update | .env update + service restart |
How can I help you explore Laravel packages today?