PHPackages                             gopal-gautam/failed-login-logger - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. gopal-gautam/failed-login-logger

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

gopal-gautam/failed-login-logger
================================

A Laravel package that listens for failed authentication events and persists them to your database for auditing, brute-force detection and incident response.

v1.0.0(1mo ago)01MITPHPPHP ^8.0

Since May 6Pushed 1mo agoCompare

[ Source](https://github.com/gopal-gautam/failed-login-logger)[ Packagist](https://packagist.org/packages/gopal-gautam/failed-login-logger)[ Docs](https://github.com/gopal-gautam/failed-login-logger)[ RSS](/packages/gopal-gautam-failed-login-logger/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (6)Versions (2)Used By (0)

Failed Login Logger for Laravel
===============================

[](#failed-login-logger-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/2035697ad347348b6986474df02b11a583c23fd6a067164e14fb0f5ca062fe21/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f676f70616c2d67617574616d2f6661696c65642d6c6f67696e2d6c6f676765722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/gopal-gautam/failed-login-logger)[![Total Downloads](https://camo.githubusercontent.com/2a21e87f6697dff210197e9e25b2b26fce2978a3d4083970b2a9ab0344727e0d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f676f70616c2d67617574616d2f6661696c65642d6c6f67696e2d6c6f676765722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/gopal-gautam/failed-login-logger)[![License](https://camo.githubusercontent.com/27aeb6bcda1026dadd122754b9a7925b2bcadcfeae88ec185c8c2224d1084ffa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f676f70616c2d67617574616d2f6661696c65642d6c6f67696e2d6c6f676765722e7376673f7374796c653d666c61742d737175617265)](LICENSE)

Persist every failed authentication attempt in your Laravel application to the database for auditing, brute-force detection and incident response. The package listens to Laravel's built-in `Illuminate\Auth\Events\Failed` event so it works with the standard `web` guard, custom guards, Sanctum, Fortify, Jetstream, Breeze and any code path that goes through Laravel's authentication infrastructure.

Features
--------

[](#features)

- Listens to `Illuminate\Auth\Events\Failed` automatically — no controller changes needed.
- Captures the supplied identifier (email, username, …), IP address, user agent, guard name and the matching `user_id` when the user exists.
- Configurable: change the table name, the model, the captured fields, the credential keys to inspect, and queue settings without forking the package.
- Optional asynchronous logging via Laravel queues.
- Built-in `MassPrunable` integration with a configurable retention window.
- Listener swallows synchronous failures (and reports them via `report()`) so a misconfigured logger can never break the login flow.
- Compatible with Laravel 9 – 12 and PHP 8.0+.

Installation
------------

[](#installation)

```
composer require gopal-gautam/failed-login-logger
```

The service provider is auto-discovered, so no manual registration is needed.

### Publish the migration and run it

[](#publish-the-migration-and-run-it)

```
php artisan vendor:publish --tag=failed-login-logger-migrations
php artisan migrate
```

### Publish the config (optional)

[](#publish-the-config-optional)

```
php artisan vendor:publish --tag=failed-login-logger-config
```

This drops `config/failed-login-logger.php` into your application where every option is documented inline.

Usage
-----

[](#usage)

Once installed and migrated the package starts recording failed logins automatically. Inspect them with the Eloquent model:

```
use GG\FailedLoginLogger\Models\FailedLoginAttempt;

// Recent attempts (last 60 minutes)
FailedLoginAttempt::recent()->latest()->get();

// Attempts for a specific email or IP
FailedLoginAttempt::forEmail('alice@example.com')->count();
FailedLoginAttempt::fromIp('203.0.113.4')->recent(15)->count();

// Resolve the related user, when the identifier matched a known account
FailedLoginAttempt::with('user')->latest()->limit(20)->get();
```

### Throttling / brute-force detection example

[](#throttling--brute-force-detection-example)

```
$count = FailedLoginAttempt::fromIp(request()->ip())->recent(15)->count();

if ($count >= 10) {
    abort(429, 'Too many failed login attempts. Please try again later.');
}
```

Configuration
-------------

[](#configuration)

Every option is in `config/failed-login-logger.php` after publishing:

KeyDefaultDescription`enabled``true`Master switch. Set to `false` to skip recording without uninstalling.`table``failed_login_attempts`Database table name.`model``FailedLoginAttempt::class`Eloquent model. Replace with your own subclass to add behaviour.`capture.ip``true`Whether to record the client IP address.`capture.user_agent``true`Whether to record the request `User-Agent`.`capture.guard``true`Whether to record the auth guard that emitted the event.`identifier_keys``['email', 'username', 'name']`Ordered list of credential keys searched for the identifier.`queue.enabled``false`Run the listener on a queue instead of synchronously.`queue.connection` / `queue.queue``null` / `null`Override the connection / queue name when queuing.`pruning.enabled``false`Allow `model:prune` to delete old rows.`pruning.retention_days``30`How long to keep records when pruning is enabled.Each option can also be controlled via environment variables — see the `env(...)` calls in the published config file.

### Asynchronous logging

[](#asynchronous-logging)

To move the database write off the request lifecycle:

```
FAILED_LOGIN_LOGGER_QUEUE=true
FAILED_LOGIN_LOGGER_QUEUE_CONNECTION=redis
FAILED_LOGIN_LOGGER_QUEUE_NAME=auth
```

When `queue.enabled` is true the listener dispatches the database write as a queued closure with `afterResponse()`, so the response is sent first and the write happens on a worker (or after the request completes when the queue is `sync`). The listener itself is *not* `ShouldQueue` — Laravel 12's dispatcher silently drops `ShouldQueue` listeners whose `shouldQueue()`returns false, so we dispatch a separate job from a regular listener instead. This works across Laravel 9–12.

### Pruning old records

[](#pruning-old-records)

The model uses Laravel's `MassPrunable` trait. After enabling pruning in the config, schedule the prune command (e.g. in `routes/console.php` on Laravel 11+):

```
use Illuminate\Support\Facades\Schedule;

Schedule::command('model:prune', [
    '--model' => [\GG\FailedLoginLogger\Models\FailedLoginAttempt::class],
])->daily();
```

### Replacing the model

[](#replacing-the-model)

```
// app/Models/FailedLoginAttempt.php
namespace App\Models;

use GG\FailedLoginLogger\Models\FailedLoginAttempt as BaseAttempt;

class FailedLoginAttempt extends BaseAttempt
{
    protected $appends = ['country'];

    public function getCountryAttribute(): ?string
    {
        return geoip()->getLocation($this->ip_address)->iso_code ?? null;
    }
}
```

```
// config/failed-login-logger.php
'model' => App\Models\FailedLoginAttempt::class,
```

Schema
------

[](#schema)

The published migration creates a table with the following columns:

ColumnTypeNotes`id``bigIncrements`Primary key.`user_id``unsignedBigInteger`, nullableIndexed. Set when identifier matches a user.`email_address``string`, nullableIndexed. The identifier supplied at login.`ip_address``string(45)`, nullableIndexed. IPv4 or IPv6.`user_agent``string(1024)`, nullableTruncated to 1024 chars.`guard``string(64)`, nullableAuth guard that emitted the event.`created_at``timestamp`Indexed for time-window queries.`updated_at``timestamp`No foreign key is added to `users` so the table can coexist with non-standard user schemas. Add one in your own migration if you need cascade behaviour.

Behind a proxy / load balancer
------------------------------

[](#behind-a-proxy--load-balancer)

`request()->ip()` returns the address of the immediate client. If your application sits behind a reverse proxy or load balancer, configure Laravel's `TrustProxies` middleware so that the `X-Forwarded-For` header is honoured. The package will then automatically capture the real client IP.

Testing
-------

[](#testing)

```
composer install
composer test
```

The suite uses Orchestra Testbench against an in-memory SQLite database.

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for release notes.

License
-------

[](#license)

Released under the [MIT License](LICENSE).

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance93

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

34d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3e60e63a914b6defeba9288a027204b0e41bb97304dc2d98a4c37a62838d43f0?d=identicon)[gopal-gautam](/maintainers/gopal-gautam)

---

Top Contributors

[![gopal-gautam](https://avatars.githubusercontent.com/u/11187799?v=4)](https://github.com/gopal-gautam "gopal-gautam (1 commits)")

---

Tags

laravelsecurityauthAuditloggerloginbrute forcefailed login

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/gopal-gautam-failed-login-logger/health.svg)

```
[![Health](https://phpackages.com/badges/gopal-gautam-failed-login-logger/health.svg)](https://phpackages.com/packages/gopal-gautam-failed-login-logger)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3325.1M337](/packages/psalm-plugin-laravel)[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k98.0M1.3k](/packages/spatie-laravel-permission)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k14.1M120](/packages/laravel-pulse)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9732.3M121](/packages/roots-acorn)[spatie/laravel-health

Monitor the health of a Laravel application

87311.3M149](/packages/spatie-laravel-health)[ytake/laravel-aspect

Aspect Oriented Programming library for laravel framework, and lumen

138140.4k1](/packages/ytake-laravel-aspect)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
