- 5 minutes read

Invalidating sessions on other devices on Laravel

Recently I had my cellphone stolen and realized how many apps don't have a session control feature. I couldn’t log out of that device.

Fortunately, Laravel provides a way to invalidate and "log out" an active user's sessions on other devices without invalidating the session on their current device.

Below, I list a few cases of when this feature might be helpful:

Invalidating Sessions On Other Devices

To invalidate the user's session on all devices except the current one, you need to call the Auth::logoutOtherDevices method. It requires the users to confirm the password.

This is important because if the user lost or had a cellphone stolen, you can't allow someone to log out of all sessions using that device.

use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($currentPassword);

For the logoutOtherDevices method to work, Laravel provides Illuminate\Session\Middleware\AuthenticateSessionmiddleware which detects password hash changes, logs out the user immediately, and fires the Illuminate\Auth\Events\CurrentDeviceLogout event.

By default, the AuthenticateSession middleware may be attached to a route using the auth.session route middleware alias as defined in your application's HTTP kernel
Official Laravel Documentation

routes/web.php

Route::middleware(['auth', 'auth.session'])->group(function () {
    Route::get('/', function () {
        // ...
    });
});

Then you might already be thinking about what the logoutOtherDevices does. It rehashes the password. Huh, but does the hash change even using the same password? Yes, it does!

Laravel Hash::make() explained

Invalidating session of a specific device

That is possible, but you must manage sessions using the database driver. This allows querying the sessions and displaying a list to the user to choose a specific session to invalidate.

The database driver needs a table. You may use the session:table artisan command to generate this migration.

php artisan session:table

php artisan migrate

Set the driver in the config/session.php file as a database:

config/session.php

//...
'driver' => env('SESSION_DRIVER', 'database')
//...

Or via SESSION_DRIVER attribute on the env file:

env

SESSION_DRIVER=database

Then create a model for the session table:

php artisan make:model Session

Create the relationships:

app/Models/Session.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Session extends Model
{
    public $incrementing = false;

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

app/Models/User.php

namespace App\Models;

//...
use Illuminate\Database\Eloquent\Relations\HasMany;

class User extends Authenticatable
{
    //...
    public function sessions(): HasMany
    {
        return $this->hasMany(Session::class);
    }
}

Now you can list the sessions:

$user = auth()->user();

$sessions = $user->sessions()
    ->select('id', 'ip_address', 'user_agent', 'last_activity')
    ->get();

dump($sessions->toArray());

Example of how it should look like:

array:3 [▼ // routes/web.php:18
  0 => array:4 [▶
    "id" => "J9KBJgsqKWRu4JGhNpTF73EBhGXD9FneIR2vzEqX"
    "ip_address" => "217.240.75.140"
    "user_agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..."
    "last_activity" => 1688043153
  ]
  1 => array:4 [▶
    "id" => "mfmRbbeR803hPpi0uLlPYtWaahqgw6CglEu5UMv7"
    "ip_address" => "21.51.178.175"
    "user_agent" => "Mozilla/5.0 (iPhone; CPU iPhone OS 11_6_9; like Mac OS X) ..."
    "last_activity" => 1688043136
  ]
  2 => array:4 [▶
    "id" => "VCkIFZN0zjKq808gvps7haz8XzOkOjnxVlZQifwe"
    "ip_address" => "25.31.180.18"
    "user_agent" => "Mozilla / 5.0 (compatible; MSIE 8.0; Windows; U; Windows NT 10.0; WOW64; en-US Trident / 4.0)"
    "last_activity" => 1688043145
  ]
]

Finally, to destroy a specific session, you need to delete it from the database. In the example below, we are disconnecting the iPhone:

$user->sessions()
    ->where('id', 'mfmRbbeR803hPpi0uLlPYtWaahqgw6CglEu5UMv7')
    ->delete();

In closing

In this post, you’ve learned the importance of session control per device and how it can be achieved using Laravel.

If you have any comments, you can share them in the discussion on Twitter.

Do you like my content?

Subscribe to my newsletter to be notified on future articles.