Support the ongoing development of Laravel.io →
Article Hero Image

Custom authentication guard in Laravel Sanctum

1 Apr, 2022 3 min read 813 views

Photo by rc.xyz NFT gallery on Unsplash

How to specify auth guard when using multiple guards with Sanctum

Preamble

Laravel Sanctum is the go-to solution for token-based API authentication and SPA (Single page application) authentication. It uses an authentication guard when performing the SPA authentication.

By default, the web guard is used as per the configuration file. The same guard is used in the default Laravel request authentication as well.

If your web app has multiple panels (say, admin, manager, customer, etc.), you'd be using multiple authentication guards. And there is a way to specify a guard to the auth middleware like:

Route::get('/setup', function () {
    // Only the users authenticated via the admin guard can visit this page.
})->middleware('auth:admin');

But in the case of Sanctum, there is no way to specify the guard. The word sanctum itself is used in the place of the guard name:

Route::get('/setup', function () {
    // The default `web` guard is used. There is no option to specify any other guard name here.
})->middleware('auth:sanctum');

How do we use the non-default guard then? Many developers have faced this issue. Let's solve it.

Solution

Step 1: Create a middleware

We will create a new middleware that will set the authentication guard for us based on the URL. Let us call it SetSanctumGuard:

<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Str;

class SetSanctumGuard
{
    public function handle($request, Closure $next)
    {
        if (Str::startsWith($request->getRequestUri(), '/api/admin/')) {
            config(['sanctum.guard' => 'admin']);
        } elseif (Str::startsWith($request->getRequestUri(), '/api/manager/')) {
            config(['sanctum.guard' => 'manager']);
        } elseif (Str::startsWith($request->getRequestUri(), '/api/customer/')) {
            config(['sanctum.guard' => 'customer']);
        }

        return $next($request);
    }
}

Assuming that our web app follows this pattern in the API endpoints, we can decide the auth guard dynamically inside the middleware. Or you can try any other way as per your web app scenario to decide the guard.

Step 2: Enable the middleware

There are multiple ways to specify a middleware. In this case, we can simply add it to the api array inside the app/Http/Kernel.php file.

protected $middlewareGroups = [
    'web' => [
        // ...
    ],

    'api' => [
        \App\Http\Middleware\SetSanctumGuard::class,
        // ...
    ],
];

Step 3: Add a note in the config file (Optional)

To assure that none of the team members (or even yourself) get surprises in the future, it is a good idea to note this in the config/sanctum.php file. I do it like:

return [
    'guard' => '', // This is set by the `SetSanctumGuard` middleware

    //...
];

And with this, your web app should be using the respective auth guard to protect the routes as per the user type.

Cheers

I hope Sanctum allows this customization in the near future. And we will not need to create a custom middleware for this use case.

Until then, enjoy this quick hack and build powerful Laravel web apps. Have fun!

Last updated 1 month ago.

driesvints, mrgiant, gauravmak liked this article

3
Like this article? Let the author know and give them a clap!
gauravmak (Gaurav Makhecha) Full-time Freelancer | Laravel, Vue.js Fan | Sharing community updates plus my learnings on freelancing, productivity, and the things in-between

Other articles you might like

Article Hero Image December 13th 2024

How to add WebAuthn Passkeys To Backpack Admin Panel

Want to make your Laravel Backpack admin panel more secure with a unique login experience for your a...

Read article
Article Hero Image December 13th 2024

Quickest way to setup PHP Environment (Laravel Herd + MySql)

Setting up a local development environment can be a time taking hassle—whether it's using Docker or...

Read article
Article Hero Image December 9th 2024

Access Route Model-Bound Models with "#[RouteParameter]"

Introduction I've recently been using the new #[RouteParameter] attribute in Laravel, and I've been...

Read article

We'd like to thank these amazing companies for supporting us

Your logo here?

Laravel.io

The Laravel portal for problem solving, knowledge sharing and community building.

© 2024 Laravel.io - All rights reserved.