PHPackages                             kirchdev/laravel-device-sessions - 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. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. kirchdev/laravel-device-sessions

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

kirchdev/laravel-device-sessions
================================

Device-bound login sessions for Laravel: per-device remember-me tokens, a "where am I signed in" device list, and revoke/rename — privacy-respecting and Fortify-agnostic.

v0.2.0(1mo ago)01[5 PRs](https://github.com/kirchDev/laravel-device-sessions/pulls)MITPHPPHP ^8.4CI passing

Since May 30Pushed 1w agoCompare

[ Source](https://github.com/kirchDev/laravel-device-sessions)[ Packagist](https://packagist.org/packages/kirchdev/laravel-device-sessions)[ Docs](https://github.com/kirchDev/laravel-device-sessions)[ RSS](/packages/kirchdev-laravel-device-sessions/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (15)Versions (9)Used By (0)

📱 laravel-device-sessions
=========================

[](#-laravel-device-sessions)

**Device-bound login sessions for Laravel — per-device "remember me" tokens, a "where am I signed in" list, and revoke/rename. Privacy-respecting and Fortify-agnostic.**

[![Latest Version on Packagist](https://camo.githubusercontent.com/a4aede87d4c46cd1f767a7d9f34d18794a2a9647283933e6c791e6cecfe09a9f/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b697263686465762f6c61726176656c2d6465766963652d73657373696f6e732e7376673f7374796c653d666c61742d73717561726526636f6c6f723d346634366535)](https://packagist.org/packages/kirchdev/laravel-device-sessions)[![Total Downloads](https://camo.githubusercontent.com/b253f3d2af1859a2eea1515f47876d6ac53cf3bf94f26c4036f5f42b9a86dc6b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6b697263686465762f6c61726176656c2d6465766963652d73657373696f6e732e7376673f7374796c653d666c61742d73717561726526636f6c6f723d346634366535)](https://packagist.org/packages/kirchdev/laravel-device-sessions)[![Tests](https://camo.githubusercontent.com/0bc85325e97fb5b47e2c8ee5bd4a7cd9a368c0c9db8acd733c15fa539bea8bc9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6b697263684465762f6c61726176656c2d6465766963652d73657373696f6e732f63692e796d6c3f6272616e63683d6d61696e267374796c653d666c61742d737175617265266c6162656c3d7465737473)](https://github.com/kirchDev/laravel-device-sessions/actions/workflows/ci.yml)[![PHP Version](https://camo.githubusercontent.com/c9a58d57ddeff7d0d20be86b52787b7af5d330da6de2fdc497c8a5c4d43c39f0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f6b697263686465762f6c61726176656c2d6465766963652d73657373696f6e732f7068703f7374796c653d666c61742d73717561726526636f6c6f723d383939336265)](https://packagist.org/packages/kirchdev/laravel-device-sessions)[![Laravel Version](https://camo.githubusercontent.com/73c5d41e3219cf9aa9f7e5f72cb51518b6bfd45db33dffe97497b4cfa741f704/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f6b697263686465762f6c61726176656c2d6465766963652d73657373696f6e732f696c6c756d696e617465253246737570706f72743f7374796c653d666c61742d737175617265266c6162656c3d6c61726176656c26636f6c6f723d666632643230)](https://packagist.org/packages/kirchdev/laravel-device-sessions)[![License: MIT](https://camo.githubusercontent.com/1315c908484699172448edaecd12bc36574aa9121c46aba6302ff809fd8c1c2c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b697263686465762f6c61726176656c2d6465766963652d73657373696f6e732e7376673f7374796c653d666c61742d73717561726526636f6c6f723d313062393831)](LICENSE)

---

```
$user->devices; // every browser signed in, with masked IP, OS and last-seen — GitHub-style
```

That's it. Concurrent device-bound remember-me tokens, a "where am I signed in" list, and revoke/rename — without touching your login controllers.

📦 Install &amp; run
-------------------

[](#-install--run)

```
composer require kirchdev/laravel-device-sessions
php artisan vendor:publish --tag=device-sessions-migrations
php artisan migrate
```

Important

Publish the config first (`--tag=device-sessions-config`) and set `device-sessions.keys.*` + `table_names.*` **before** migrating — the migrations read config at run time, and `keys.user_key_type` must match your users-table primary key.

Add the `HasDeviceSessions` trait to your authenticatable model and point its auth provider at the device-aware driver:

```
use KirchDev\DeviceSessions\Concerns\HasDeviceSessions;

class User extends Authenticatable
{
    use HasDeviceSessions;
}
```

```
// config/auth.php
'providers' => [
    'users' => [
        'driver' => 'device-aware-eloquent', // was 'eloquent'
        'model' => App\Models\User::class,
    ],
],
```

Then alias the tracking middleware and attach it to your authenticated routes — that's the whole wiring; remember-me logins are now device-bound and the device list populates automatically:

```
// bootstrap/app.php
use KirchDev\DeviceSessions\Http\Middleware\TrackAuthenticatedUserDevice;

->withMiddleware(fn (Middleware $middleware) => $middleware->alias([
    'track.device' => TrackAuthenticatedUserDevice::class,
]))
```

```
Route::middleware(['auth', 'track.device'])->group(function () {
    // ...authenticated routes
});
```

✨ Features
----------

[](#-features)

- **🔐 Device-bound remember-me** — a custom `device-aware-eloquent` driver binds each remember token to a device row + cookie instead of the single `remember_token` column (one active token per device, rotated on login).
- **📋 "Where am I signed in"** — list active devices (OS, friendly name, masked IP, last-seen), revoke one, revoke all others, or rename — all as plain actions.
- **🕵️ Privacy-respecting** — IP masking on by default (IPv4 → /24, IPv6 → /48), swappable via the `IpMasker` contract.
- **🔌 Fortify-agnostic** — works under any login mechanism; the two-factor cookie bridge auto-wires only when Fortify is present.
- **🧩 Overridable everything** — name parsing, OS detection, cookie policy, IP masking and token hashing are contracts with sensible defaults.
- **🧰 Config-driven schema** — models, table names and key types (`id` / `uuid` / `ulid`) all overridable.
- **📡 Event-driven** — a `DeviceTouched` event lets you react without the package assuming your schema.
- **🧪 Library-grade** — Pest 4 + Testbench, no host app needed.

📋 Managing devices
------------------

[](#-managing-devices)

The package ships **no routes** — every operation is a plain action you call from your own controllers, so the response shape stays yours:

```
use KirchDev\DeviceSessions\Actions\{ListUserDevices, RevokeUserDevice, RevokeOtherUserDevices, UpdateUserDeviceName};

$devices = app(ListUserDevices::class)->execute($user);          // active devices, last-seen first
app(RevokeUserDevice::class)->execute($user, $deviceId);         // revoke one (+ its tokens)
app(RevokeOtherUserDevices::class)->execute($user, $currentId);  // keep only the current device
app(UpdateUserDeviceName::class)->execute($user, $deviceId, 'Work Laptop');
```

The middleware exposes the active device as the `current_device_id` request attribute (also `$user->currentDevice()`), so you can flag "this device" in the list.

🧩 Overridable contracts
-----------------------

[](#-overridable-contracts)

Every host-facing behaviour is a contract bound to a `Default*` — rebind any of them in a service provider:

```
$this->app->bind(
    \KirchDev\DeviceSessions\Contracts\IpMasker::class,
    \App\Support\MyStrictIpMasker::class,
);
```

All contracts and their defaultsContractDefaultControls`DeviceResolver``ResolveOrCreateUserDevice…`cookie → bootstrap-cache → create flow`DeviceNameResolver``DefaultDeviceNameResolver`User-Agent → "Chrome on Windows"`OsFamilyDetector``DefaultOsFamilyDetector`User-Agent → `DeviceOsFamily``DeviceCookieFactory``DeviceCookieBuilder`device cookie name / TTL / SameSite`IpMasker``DefaultIpMasker`IP minimisation (IPv4 /24, IPv6 /48)`RememberTokenHasher``Sha256RememberTokenHasher`at-rest token hashing📡 Events &amp; Fortify
----------------------

[](#-events--fortify)

`TouchDeviceLastSeen` fires `DeviceTouched` on a real (throttled) touch — listen instead of patching the package, e.g. to stamp your own user column:

```
Event::listen(fn (DeviceTouched $event) => $event->user->forceFill(['last_seen_at' => now()])->save());
```

Two opt-in integrations:

- **`OtherDeviceLogout`** → revokes all other devices (mirrors `Auth::logoutOtherDevices()`); toggle via `device-sessions.events`.
- **Fortify two-factor** → a listener queues the device cookie at the 2FA challenge (where the `Login` event hasn't fired yet), auto-wired via `class_exists` so Fortify is never required. Using another 2FA flow? Write your own bridge against the `DeviceResolver` contract.

🧹 Pruning revoked devices
-------------------------

[](#-pruning-revoked-devices)

Revoked devices are kept (audit/undo window), then pruned. The command ships **unscheduled** — wire it into your scheduler with `Schedule::command('device-sessions:prune')->dailyAt('03:10')`:

```
php artisan device-sessions:prune            # retention from device-sessions.prune.retention_days (180)
php artisan device-sessions:prune --days=90
```

⚙️ Configuration
----------------

[](#️-configuration)

`config/device-sessions.php` is parameterised with inline docs — e.g. rename the cookie or switch key types:

```
'cookie' => ['name' => 'device', 'same_site' => 'lax'],
'keys'   => ['primary_key_type' => 'id', 'user_key_type' => 'id'],
```

All configuration keysKeyWhat it controls`models.*`Swap the `user` / `device` / `remember_token` Eloquent models.`table_names.*`Override defaults if they collide with existing tables.`keys.*``id` / `uuid` / `ulid` for device PKs and the user FK. Set **before** migrating.`cookie.*`Device cookie name (default `device`), lifetime, SameSite, secure.`cache.*`Cache store, key prefix, login→2FA bootstrap TTL, last-seen throttle.`remember.lifetime`Minutes until a remember token expires (`null` = never).`events.*`Toggle the core event listeners.`prune.retention_days`Retention window for the prune command (default 180).🧪 Testing
---------

[](#-testing)

```
composer install
composer test       # Pest 4
composer pint       # Laravel Pint (test mode)
composer larastan   # Larastan / PHPStan
```

The test suite runs via Testbench + in-memory SQLite — no host app required.

🤝 Contributing
--------------

[](#-contributing)

PRs welcome. Conventional Commits required (enforced via commitlint). Husky runs Pint + Larastan + oxlint + oxfmt on `git commit`, so you can mostly forget about style.

Tip

Run `pnpm check:fix` (Node tooling) and `composer pint:fix` (PHP) before pushing — CI will catch what husky missed.

🛣️ Versioning
-------------

[](#️-versioning)

[Semantic Versioning](https://semver.org/). Release notes in [CHANGELOG.md](CHANGELOG.md) — managed by [release-please](https://github.com/googleapis/release-please).

📄 License
---------

[](#-license)

[MIT](LICENSE) © [Titus Kirch](https://github.com/TitusKirch/) / [IT-Dienstleistungen Titus Kirch](https://kirch.dev)

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance94

Actively maintained with recent releases

Popularity1

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

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

55d ago

### Community

Maintainers

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

---

Top Contributors

[![TitusKirch](https://avatars.githubusercontent.com/u/16943133?v=4)](https://github.com/TitusKirch "TitusKirch (28 commits)")[![kirchdev-release[bot]](https://avatars.githubusercontent.com/in/3831936?v=4)](https://github.com/kirchdev-release[bot] "kirchdev-release[bot] (1 commits)")

---

Tags

authenticationdevice-managementdeviceslaravelremember-mesecuritysessionslaravelsecurityAuthenticationsessionsremember-meDevicesdevice-management

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/kirchdev-laravel-device-sessions/health.svg)

```
[![Health](https://phpackages.com/badges/kirchdev-laravel-device-sessions/health.svg)](https://phpackages.com/packages/kirchdev-laravel-device-sessions)
```

###  Alternatives

[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M133](/packages/roots-acorn)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[laravel/pulse

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

1.7k15.1M136](/packages/laravel-pulse)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

255.2k](/packages/aedart-athenaeum)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1613.3k4](/packages/masterix21-laravel-licensing)

PHPackages © 2026

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