If you have been using the excellent spatie/laravel-activitylog to track user activities in your Laravel application, then it is only make sense to also extend it to log all related authentication events. This includes tracking when a user:

  • Logging in to the site
  • Logging out from the site (including logging out from the current device or from the other devices)
  • Failing to log in
  • Registering to the site
  • Verifying their email address
  • Resetting their password

To get started, create a new event listener that we will then register in the EventServiceProvider for all related auth events.

1
php artisan make:listener LogAuthEvent

We can then register the newly created event listener in our EventServiceProvider like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

// app/Providers/EventServiceProvider.php

...

protected $listen = [
    CurrentDeviceLogout::class => [
        LogAuthEvent::class,
    ],
    Failed::class => [
        LogAuthEvent::class,
    ],
    Login::class => [
        LogAuthEvent::class,
    ],
    Logout::class => [
        LogAuthEvent::class,
    ],
    OtherDeviceLogout::class => [
        LogAuthEvent::class,
    ],
    PasswordReset::class => [
        LogAuthEvent::class,
    ],
    Registered::class => [
        LogAuthEvent::class,
    ],
    Verified::class => [
        LogAuthEvent::class,
    ],
];
    
...

We are choosing these events simply because all of them has the same public property $user that we will use to log the events. Once we have the listener registered, then we simply log these events via the activity() helper provided by the package.

The listener class is fairly simple.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

<?php

namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Str;
use ReflectionClass;

class LogAuthEvent implements ShouldQueue
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
    }

    /**
     * Handle the event.
     */
    public function handle(object $event): void
    {
        $type = Str::of((new ReflectionClass($event))->getShortName())->kebab();

        if ($event->user) {
            activity()
                ->causedBy($event->user)
                ->performedOn($event->user)
                ->event($type)
                ->log($type);
        }
    }
}

We simply convert the event name to the kebab-case version of it, so for example OtherDeviceLogout will be stored as other-device-logout, Login as login and so on. We also set the causer and subject to the same user.

You can see other available methods available in the official documentation but for our use cases, this is sufficient for our purposes.

The next time users are doing the above events, it will be recorded accordingly to the database.

Bonus - Checking user last login

To fetch the last login timestamp for a specific user, we can use the Spatie/ActivityLog/Models\Activity to do so. Assuming the user is stored in the $user variable, then retrieving the last login timestamp will be as simple as fetching the most recent related activity as below:

$activity = Activity::forSubject($user)->forEvent('login')->latest()->first();

The timestamp will be available as the $activity->created_at property as you would expect.