Laravel · Email breach checks
Check email breaches in Laravel with a queued listener
Laravel fires Illuminate\Auth\Events\Registered when a user signs up, both in the starter kits and in controllers that call event(new Registered($user)). The CheckEmailBreaches listener implements ShouldQueue, so the Finowl lookup runs on a queue worker instead of slowing the registration request. It filters breaches to those whose DataClasses include Passwords and notifies the user with each breach Title and BreachDate.
InteractsWithQueue provides the control the error handling needs. A 429 with rate_limited calls release with the Retry-After seconds, putting the same job back on the queue. A 400 or 401 deletes the job after logging, since retrying cannot fix bad input or a wrong key. Everything else, including quota_exceeded and 5xx responses, marks the job failed so it appears in failed_jobs without being retried.
Steps
- 1
Generate the listener with php artisan make:listener and replace its contents with the example.
- 2
Create an EmailFoundInBreaches notification that tells the user which breaches leaked passwords.
- 3
Rely on event discovery, or register the listener for the Registered event yourself.
- 4
Run php artisan queue:work and register a test account to watch the job process.
- 5
Review failed_jobs for quota or server errors before retrying any of them by hand.
php artisan make:rule NotBreachedPassword
php artisan make:listener CheckEmailBreaches --event="Illuminate\Auth\Events\Registered"
php artisan make:job EnrichCustomerGender<?php
// app/Listeners/CheckEmailBreaches.php
namespace App\Listeners;
use App\Exceptions\FinowlException;
use App\Notifications\EmailFoundInBreaches;
use Illuminate\Auth\Events\Registered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class CheckEmailBreaches implements ShouldQueue
{
use InteractsWithQueue;
public int $tries = 5;
public function handle(Registered $event): void
{
$user = $event->user;
$response = Http::finowl()->post('/v1/breaches/email', ['email' => $user->email]);
if ($response->failed()) {
$error = FinowlException::fromResponse($response);
if ($error->status === 429 && $error->errorCode === 'rate_limited') {
$this->release($error->retryAfter ?? 30); // requeue this job after Retry-After
return;
}
if (in_array($error->status, [400, 401], true)) {
Log::error('Finowl email check rejected', ['user' => $user->id, 'code' => $error->errorCode]);
$this->delete(); // retrying cannot fix bad input or a bad key
return;
}
$this->fail($error); // quota or 5xx: the lookup may have run, so no blind retry
return;
}
$leakedPasswords = collect($response->json('breaches'))
->filter(fn (array $b) => in_array('Passwords', $b['DataClasses'], true))
->map(fn (array $b) => "{$b['Title']} ({$b['BreachDate']})")
->values();
if ($leakedPasswords->isNotEmpty()) {
$user->notify(new EmailFoundInBreaches($leakedPasswords->all()));
}
}
}IN PRODUCTION
Production tips
Set public int $tries high enough to cover several rate-limit releases. Each release counts as an attempt, so a low value can fail a job that only needed to wait a little longer.
Use Http::fake in feature tests to return a breached response and Notification::fake to assert the notification was sent, so your suite never calls the real API or spends credits.
Skip the notification for breaches where IsVerified is false, or word it more softly, so users are not alarmed by exposures that have not been confirmed.
Each lookup costs 1 credit, with 100 free credits every month. See pricing and error codes.
A FEW GOOD QUESTIONS
Common questions
Related guides
- Validate breached passwords with a Laravel rule
- Queue gender enrichment jobs in Laravel
- Check email breaches in Python with requests
- Check email breaches in Node.js with fetch
- Check email breaches in TypeScript with typed results
- Check email breaches in Go with net/http
- Email breach checks for fintech signups and logins
- Email breach checks for online stores and shopper logins
- Email breach checks for SaaS logins and admins
Check email breaches in Laravel with a queued listener
Grab an API key, paste the example and run it. 100 free credits every month.