pijler/user-devices

This package provides support for managing user devices.

Installs: 20

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/pijler/user-devices

v0.2.1 2026-02-02 19:06 UTC

This package is auto-updated.

Last update: 2026-02-02 19:06:34 UTC


README

This package provides support for managing user devices in Laravel. Track login devices, detect new logins, send notifications, and allow users to block suspicious devices—useful for security monitoring, session management, and multi-device applications.

🧩 Features

  • Device tracking: Automatic tracking of IP address and user agent
  • New login detection: Identifies first-time logins from new devices
  • Email notifications: Sends alerts when a new device logs in
  • Block device: Signed links to block suspicious devices
  • Integrated middleware: Protect routes from blocked devices
  • Model trait: Simple Eloquent integration
  • Flexible configuration: Custom models and callbacks

📦 Installation

You can install the package via Composer:

composer require pijler/user-devices

🗄️ Publishing Migrations

Publish the package migrations:

php artisan vendor:publish --tag=user-devices-migrations

Run the migrations:

php artisan migrate

⚙️ Configuration

Basic Configuration

The package works out-of-the-box, but you can customize the behavior:

use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\URL;
use UserDevices\DeviceCreator;
use UserDevices\Notifications\NewLoginDeviceNotification;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
        // Use custom user model
        DeviceCreator::useUserModel(CustomUser::class);

        // Use custom user device model
        DeviceCreator::useUserDeviceModel(CustomUserDevice::class);

        // Customize user agent generation
        DeviceCreator::userAgentUsing(fn ($userAgent) => substr($userAgent, 0, 255));

        // Control when to send new login notifications (e.g. disable in local/staging)
        DeviceCreator::shouldSendNotificationUsing(function ($user, $device) {
            return ! app()->environment('local');
        });

        // Customize the notification email
        NewLoginDeviceNotification::toMailUsing(function ($notifiable, $device) {
            $expire = Config::get('auth.verification.expire', 60);

            $blockUrl = URL::temporarySignedRoute(
                name: 'user-devices.block',
                expiration: Carbon::now()->addMinutes($expire),
                parameters: [
                    'id' => $device->getKey(),
                    'hash' => sha1($device->getKey()),
                ],
            );

            return (new MailMessage)
                ->subject('New device detected')
                ->line('We detected a new login to your account.')
                ->action('Block device', $blockUrl);
        });

        // Customize the block device URL
        NewLoginDeviceNotification::createBlockUrlUsing(function ($device) {
            return URL::temporarySignedRoute(
                name: 'your-custom-route-name',
                expiration: Carbon::now()->addMinutes(120),
                parameters: [
                    'id' => $device->getKey(),
                    'hash' => sha1($device->getKey()),
                ],
            );
        });
    }
}

The block link expiration uses auth.verification.expire (default 60 minutes), same as Laravel's email verification.

🧠 Usage

1. Using the HasUserDevices Trait

Add the HasUserDevices trait to your User model. Your User model must also use the Notifiable trait for notifications:

use Illuminate\Notifications\Notifiable;
use UserDevices\Traits\HasUserDevices;

class User extends Authenticatable
{
    use HasUserDevices;
    use Notifiable;
}

2. Saving User Devices

The package automatically saves user devices when the Authenticated event is fired (on every authenticated request). No manual setup required—just add the HasUserDevices trait to your User model.

To ignore the new login notification via request context (e.g. in middleware or controller before authentication):

use UserDevices\DeviceCreator;

// In middleware or controller—call before the user is authenticated
DeviceCreator::ignoreNotification();

To control notifications globally (e.g. disable in local/staging, or custom logic per user/device):

use UserDevices\DeviceCreator;

// Disable notifications entirely
DeviceCreator::shouldSendNotificationUsing(fn () => false);

// Custom logic (e.g. skip for admins)
DeviceCreator::shouldSendNotificationUsing(fn ($user, $device) => ! $user->isAdmin());

// Only send in production
DeviceCreator::shouldSendNotificationUsing(fn ($user, $device) => app()->environment('production'));

This will:

  • Create or update the device record (IP + user agent)
  • Update last activity timestamp
  • Send a notification email on first login from that device (unless ignoreNotification() was called or shouldSendNotificationUsing() returns false)

3. Block Device Route

When a user receives the new login notification email, they can click a link to block the device. Register a route that handles this request. The route must be signed and named user-devices.block:

use UserDevices\Http\Requests\BlockDeviceRequest;

Route::get('/devices/block/{id}/{hash}', function (BlockDeviceRequest $request) {
    $request->fulfill();

    return redirect()->route('home')->with('message', 'Device blocked successfully.');
})->middleware(['signed', 'throttle:6,1'])->name('user-devices.block');

You can use any path you prefer (e.g. /user-devices/block/{id}/{hash}) as long as the route is named user-devices.block and includes the {id} and {hash} parameters.

4. Using the Middleware

The package includes middleware to block requests from devices the user has blocked:

// routes/web.php
use Illuminate\Support\Facades\Route;

Route::middleware(['auth', 'check.device'])->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
});

When a blocked device tries to access a protected route, the middleware returns 423 Locked.

5. Working with the UserDevice Model

use UserDevices\Models\UserDevice;

// Get user's devices
$devices = $user->userDevices;

// Block a device
$device = UserDevice::find($id);
$device->block();

// Unblock a device
$device->unblock();

// Block by ID (static)
UserDevice::markAsBlocked($id);

// Unblock by ID (static)
UserDevice::markAsUnblocked($id);

6. Sending Notifications Manually

$user->sendNewLoginDeviceNotification($device);

🧩 API Reference

DeviceCreator

// Configuration
DeviceCreator::useUserModel(string $model): void
DeviceCreator::useUserDeviceModel(string $model): void
DeviceCreator::userAgentUsing(Closure $callback): void
DeviceCreator::shouldSendNotificationUsing(Closure $callback): void  // (user, device) => bool

// Methods
DeviceCreator::ignoreNotification(): void  // Add to Context to skip notification for current request

UserDevice Model

// Relationships
$device->user(): BelongsTo

// Actions
$device->block(): void
$device->unblock(): void

// Static methods
UserDevice::markAsBlocked(mixed $id): void
UserDevice::markAsUnblocked(mixed $id): void

HasUserDevices Trait

// Methods available on model
$model->userDevices(): HasMany
$model->sendNewLoginDeviceNotification(UserDevice $device): void

NewLoginDeviceNotification

// Configuration
NewLoginDeviceNotification::toMailUsing(Closure $callback): void
NewLoginDeviceNotification::createBlockUrlUsing(Closure $callback): void

BlockDeviceRequest

// Methods
$request->fulfill(): void
$request->getDevice(): ?UserDevice

📝 License

Open-source under the MIT license.

🚀 Thanks!