PHPackages                             harryes/laravel-sentinellog - 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. harryes/laravel-sentinellog

ActiveLaravel-package[Logging &amp; Monitoring](/categories/logging)

harryes/laravel-sentinellog
===========================

A vigilant authentication logging and security package for Laravel 10-13.

v0.2.1(1w ago)81331MITPHPPHP ^8.2|^8.3|^8.4CI passing

Since Jun 4Pushed 1w ago1 watchersCompare

[ Source](https://github.com/Harish120/laravel-sentinellog)[ Packagist](https://packagist.org/packages/harryes/laravel-sentinellog)[ Docs](https://github.com/harryes/laravel-sentinellog)[ RSS](/packages/harryes-laravel-sentinellog/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (36)Versions (7)Used By (0)

Laravel SentinelLog
===================

[](#laravel-sentinellog)

[![License](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/50b13d3d01778282febe11a92c7166976ae637e4ee8ffe64bce210549ed5e096/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e32253230253743253230382e33253230253743253230382e342d626c7565)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/48d1540dd6648060fa0a10d77abde702775e583cdee94c86bad1264226695ac4/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31302e7825323025374325323031312e7825323025374325323031322e7825323025374325323031332e782d626c7565)](https://laravel.com)

**Laravel SentinelLog** is a powerful, all-in-one authentication logging and security package for Laravel. It provides advanced features like device tracking, 2FA, session management, brute force protection, geo-fencing, and SSO support, ensuring security while keeping users informed.

Features
--------

[](#features)

- **Authentication Logging**: Logs login, logout, and failed attempts.
- **Device &amp; Geolocation Tracking**: Tracks devices and locations for authentication events.
- **Notifications**: Alerts for new device logins and failed attempts.
- **Two-Factor Authentication (2FA)**: TOTP-based 2FA with QR code support.
- **Session Management**: Tracks multiple sessions and detects hijacking.
- **Brute Force Protection**: Rate-limits login attempts and blocks suspicious IPs.
- **Geo-Fencing**: Restricts logins to specific countries.
- **Single Sign-On (SSO)**: Token-based SSO for seamless authentication.
- **New Location Verification**: Detects logins from unrecognised locations and emails the user a verify/deny link, invalidating the session on denial.

Demo Project
------------

[](#demo-project)

Want to see Laravel SentinelLog in action? Check out our demo project:

### [Laravel SentinelLog Demo](https://github.com/Harish120/sentinel-test)

[](#laravel-sentinellog-demo)

This demo project showcases:

- Complete authentication system with SentinelLog integration
- Real-world implementation of all features
- Best practices for configuration and usage
- Example of custom notifications and event handling
- Interactive UI for testing various security features

To run the demo locally:

```
git clone https://github.com/Harish120/sentinel-test.git
cd sentinel-test
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan db:seed
php artisan serve
```

Visit `http://localhost:8000` to explore the demo.

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

[](#installation)

### Prerequisites

[](#prerequisites)

- PHP 8.2 or higher
- Laravel 10.x, 11.x, 12.x, or 13.x
- Composer

### Steps

[](#steps)

1. **Install the Package**

```
  composer require harryes/laravel-sentinellog
```

2. **Publish Configuration**

```
  php artisan vendor:publish --tag=sentinel-log-config
```

2a. *(Optional)* **Publish Views** — to customise the verify/deny confirmation pages:

```
  php artisan vendor:publish --tag=sentinel-log-views
```

This copies the Blade templates to `resources/views/vendor/sentinel-log/location/`.

3. **Run Migrations**

```
  php artisan migrate
```

4. **Add Trait to User Model**

```
    use Harryes\SentinelLog\Traits\NotifiesAuthenticationEvents;

    class User extends Authenticatable
    {
        use NotifiesAuthenticationEvents;

        protected $fillable = ['two_factor_secret', 'two_factor_enabled_at'];
        protected $casts = [
            'two_factor_enabled_at' => 'datetime',
            'two_factor_secret'     => 'encrypted', // encrypts the TOTP secret at rest
        ];
    }
```

> **Security:** The `encrypted` cast uses your application's `APP_KEY` to encrypt the 2FA secret in the database. A database dump will not expose raw TOTP secrets. If you have existing unencrypted secrets, re-generate them after adding the cast — existing codes will stop working until the secret is re-saved through the encryption layer.

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

[](#configuration)

Edit `config/sentinel-log.php` to customize the package. Key options:

### General Settings

[](#general-settings)

```
    'enabled' => true,
    'events' => ['login' => true, 'logout' => true, 'failed' => true],
    'table_name' => 'authentication_logs',
```

### Notifications

[](#notifications)

```
    'new_device'        => ['enabled' => true, 'channels' => ['mail'], 'threshold' => 1],
    'failed_attempt'    => ['enabled' => true, 'channels' => ['mail'], 'threshold' => 3, 'window' => 60],
    'session_hijacking' => ['enabled' => true, 'channels' => ['mail']],
```

To also persist notifications to the database, add `'database'` to the channels array for any notification. Your `users` table must have the `notifications` table from `php artisan notifications:table`.

```
    'new_device' => ['enabled' => true, 'channels' => ['mail', 'database']],
```

> **Note:** The `NewLocationLogin` database payload stores `verification_id` (the record's primary key) rather than the raw token, so the verify/deny URLs cannot be reconstructed from the notifications table.

### Two-Factor Authentication (2FA)

[](#two-factor-authentication-2fa)

```
    'two_factor' => [
        'enabled'     => false,
        'required'    => false, // when true, all TwoFactorAuthenticatable users must complete 2FA setup
        'middleware'  => 'sentinel-log.2fa',
        'setup_route' => 'two-factor.setup',
    ],
```

- `enabled` — registers the `sentinel-log.2fa` middleware alias so you can apply it to routes
- `required` — when `true`, the middleware redirects **any** user who has not set up 2FA to the setup route; when `false` (default), only users who have already set up 2FA are prompted to verify

> **Important:** The package does not register a `two-factor.setup` route — you must define it in your own application. If your route has a different name, set `setup_route` to match or use the `SENTINEL_LOG_2FA_SETUP_ROUTE` env variable.

### Sessions

[](#sessions)

```
    'sessions' => ['enabled' => true, 'max_active' => 5],
```

### Brute Force Protection

[](#brute-force-protection)

```
    'brute_force' => ['enabled' => true, 'threshold' => 5, 'window' => 15, 'block_duration' => 24],
```

### Geolocation Provider

[](#geolocation-provider)

```
    // Defaults to ipwho.is — free, HTTPS, no API key required.
    // Override to use your own provider; must return JSON compatible with ipwho.is response format.
    'geo_provider_url' => 'https://ipwho.is',
```

### Geo-Fencing

[](#geo-fencing)

```
    'geo_fencing' => ['enabled' => false, 'allowed_countries' => ['United States', 'Canada']],
```

### SSO

[](#sso)

```
    'sso' => ['enabled' => false, 'client_id' => 'default_client', 'token_lifetime' => 24],
```

### New Location Verification

[](#new-location-verification)

```
    'location_verification' => [
        'enabled' => true,
        'channels' => ['mail'],
        'token_ttl' => 30, // Minutes until verify/deny links expire
        'redirect_after_verify' => '/',
        'redirect_after_deny' => '/',
    ],
```

### Environment Variables

[](#environment-variables)

Add these to `.env`:

```
    SENTINEL_LOG_ENABLED=true
    SENTINEL_LOG_2FA_ENABLED=true
    SENTINEL_LOG_2FA_REQUIRED=false
    SENTINEL_LOG_2FA_SETUP_ROUTE=two-factor.setup
    SENTINEL_LOG_GEO_PROVIDER_URL=https://ipwho.is
    SENTINEL_LOG_GEO_FENCING_ENABLED=true
    SENTINEL_LOG_GEO_FENCING_ALLOWED_COUNTRIES="United States,Canada"
    SENTINEL_LOG_LOCATION_VERIFICATION_ENABLED=true
```

Usage Examples
--------------

[](#usage-examples)

### 2FA Setup

[](#2fa-setup)

Generate a 2FA secret and QR code:

```
    use Harryes\SentinelLog\Services\TwoFactorAuthenticationService;

    $service = new TwoFactorAuthenticationService();
    $user->update([
        'two_factor_secret' => $service->generateSecret(),
        'two_factor_enabled_at' => now(),
    ]);
    $qrCodeUrl = $service->getQrCodeUrl($user->two_factor_secret, $user->email);
```

Protect routes with 2FA middleware:

```
    Route::middleware('sentinel-log.2fa')->group(function () {
        Route::get('/dashboard', fn() => 'Protected!');
    });
```

Verify 2FA code:

```
    Route::post('/2fa/verify', function (TwoFactorAuthenticationService $service) {
        if ($service->verifyCode(auth()->user()->two_factor_secret, request('code'))) {
            session(['2fa_verified' => true]);
            return redirect('/dashboard');
        }
        return back()->withErrors(['code' => 'Invalid 2FA code']);
    });
```

### Failed Login Attempt Notifications

[](#failed-login-attempt-notifications)

To receive notifications when a user's account hits the failed attempt threshold, implement the `NotifiableWithFailedAttempt` contract on your User model alongside the `NotifiesAuthenticationEvents` trait:

```
use Harryes\SentinelLog\Contracts\NotifiableWithFailedAttempt;
use Harryes\SentinelLog\Models\AuthenticationLog;
use Harryes\SentinelLog\Traits\NotifiesAuthenticationEvents;

class User extends Authenticatable implements NotifiableWithFailedAttempt
{
    use NotifiesAuthenticationEvents;

    public function notifyFailedAttempt(AuthenticationLog $log): void
    {
        $this->notify(new YourFailedAttemptNotification($log));
    }
}
```

The method is called automatically by the `LogFailedLogin` listener once the threshold defined in `notifications.failed_attempt.threshold` is reached within the configured time window.

### SSO Integration

[](#sso-integration)

Generate an SSO token:

```
    use Harryes\SentinelLog\Services\SsoAuthenticationService;

    $ssoService = new SsoAuthenticationService();
    $token = $ssoService->generateToken(auth()->user(), 'client_app_1');
```

Handle SSO login in the client app:

```
    Route::get('/sso/login', fn() => 'Logged in via SSO')->middleware('auth');
```

### Device Recognition

[](#device-recognition)

SentinelLog uses a **persistent cookie token** as the primary device identity signal — the same approach used by GitHub, Google, and Stripe.

**How it works:**

- On first login from a browser, a cryptographically random 64-character token is generated and stored in a long-lived `sentinel_device_token` cookie (2 years, HttpOnly, SameSite=Lax)
- On every subsequent login, the cookie is read and looked up in the login history
- If the token is not found → new device → `NewDeviceLogin` notification sent
- If the token is found → recognised device → no notification

**Why a cookie and not a header hash?**
Header-based hashes that include the IP address break for mobile users (WiFi ↔ cellular), dynamic IPs, and VPN users. The cookie token is stable across all of these. A secondary header hash (User-Agent + Accept-Language + Accept-Encoding) is still stored in `device_info` alongside the token for forensic reference.

**To enable new device notifications**, set in config:

```
'notifications' => [
    'new_device' => ['enabled' => true, 'channels' => ['mail']],
],
```

> **Upgrading from a previous version?** Existing login records have no `token` field in `device_info`. Each user will receive a single "new device" email on their first login after the upgrade — after which the cookie is set and recognition is stable.

### Session Management

[](#session-management)

View active sessions:

```
    $sessions = auth()->user()->authenticationLogs()->with('session')->get();
```

### Brute Force &amp; Geo-Fencing

[](#brute-force--geo-fencing)

Attempts are automatically rate-limited, and IPs are blocked after exceeding the threshold. Geo-fencing blocks logins from unallowed countries based on `config/sentinel-log.php`.

### New Location Verification

[](#new-location-verification-1)

When a user logs in from a city/country they have never used before, SentinelLog automatically sends them a `NewLocationLogin` notification with two action links:

- **Yes, this was me** — opens a confirmation page. The user clicks confirm which submits a `POST` request, marking the location as trusted and logging a `location_verified` event.
- **No, deny this login** — opens a confirmation page showing the location and IP details. The user clicks confirm which submits a `POST` request to revoke the session, logging a `location_denied` event.

> **Why confirmation pages for both links?** Email security scanners (Outlook Safe Links, Apple Mail, Gmail) automatically follow every link in an email on delivery. Without a confirmation step, scanners would silently trust or revoke the session before the user even reads the email.

Both confirmation pages are Blade templates you can customise — see the installation steps above.

The links expire after `token_ttl` minutes (default 30). No application code changes are required — the check runs inside the `LogSuccessfulLogin` listener on every login.

To disable the feature:

```
SENTINEL_LOG_LOCATION_VERIFICATION_ENABLED=false
```

To prune expired, unactioned verification records:

```
    use Harryes\SentinelLog\Services\LocationVerificationService;

    app(LocationVerificationService::class)->pruneExpired();
```

Scheduled Maintenance
---------------------

[](#scheduled-maintenance)

SentinelLog accumulates records over time. Add these to your scheduler to keep tables clean:

```
// routes/console.php (Laravel 11+) or App\Console\Kernel (Laravel 10)
use Harryes\SentinelLog\Services\BruteForceProtectionService;
use Harryes\SentinelLog\Services\LocationVerificationService;

Schedule::call(fn () => app(BruteForceProtectionService::class)->pruneExpired())
    ->daily()
    ->name('sentinel-log:prune-blocked-ips');

Schedule::call(fn () => app(LocationVerificationService::class)->pruneExpired())
    ->daily()
    ->name('sentinel-log:prune-location-verifications');
```

MethodWhat it cleansRecommended frequency`BruteForceProtectionService::pruneExpired()`Expired IP block records from `sentinel_blocked_ips`Daily`LocationVerificationService::pruneExpired()`Expired unactioned location verification tokensDaily> **Note on IP blocks:** A blocked IP is considered inactive once its `expires_at` timestamp passes — no record deletion is needed for the block to stop working. `pruneExpired()` is purely a housekeeping concern.

Contributing
------------

[](#contributing)

Submit issues or pull requests on GitHub. Feedback is welcome!

License
-------

[](#license)

This package is open-sourced under the MIT License.

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance98

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 87.5% 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

Every ~95 days

Total

5

Last Release

12d ago

PHP version history (3 changes)v0.0.1PHP ^7.4|^8.0|^8.1|^8.2|^8.3

v0.0.2PHP ^8.1|^8.2|^8.3|^8.4

v0.1.0PHP ^8.2|^8.3|^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/c54cb41297fa3b2ecdf2284923115a78e643fec7a1967176a3a89eec0ad6f5ab?d=identicon)[Harish120](/maintainers/Harish120)

---

Top Contributors

[![Harish120](https://avatars.githubusercontent.com/u/27349710?v=4)](https://github.com/Harish120 "Harish120 (147 commits)")[![anilkumarthakur60](https://avatars.githubusercontent.com/u/16583802?v=4)](https://github.com/anilkumarthakur60 "anilkumarthakur60 (15 commits)")[![harishtechdev](https://avatars.githubusercontent.com/u/190347082?v=4)](https://github.com/harishtechdev "harishtechdev (4 commits)")[![StyleCIBot](https://avatars.githubusercontent.com/u/11048387?v=4)](https://github.com/StyleCIBot "StyleCIBot (2 commits)")

---

Tags

loglaravelsecurityAuthenticationlaravel-packagesentinel

###  Code Quality

TestsPest

Static AnalysisPHPStan

### Embed Badge

![Health badge](/badges/harryes-laravel-sentinellog/health.svg)

```
[![Health](https://phpackages.com/badges/harryes-laravel-sentinellog/health.svg)](https://phpackages.com/packages/harryes-laravel-sentinellog)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M131](/packages/roots-acorn)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M167](/packages/spatie-laravel-health)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.6k29.9M148](/packages/laravel-cashier)[laravel/pulse

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

1.7k15.1M132](/packages/laravel-pulse)[fleetbase/core-api

Core Framework and Resources for Fleetbase API

1235.9k20](/packages/fleetbase-core-api)

PHPackages © 2026

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