laravelauthenticationmodelsingle-page-applicationlaravel-sanctum

Laravel sanctum SPA authentication with multiple different user models


I'd like to implement authentication in Laravel 11/12. I am using Laravel as an API that is consumed by two Angular SPA's on the same domain (different subdomains): call it the admin frontend and the client frontend.

For the admin frontend, I have an AdminUser model, with fields email, password, role, foo, etc., and for the client frontend, a ClientUser with fields like email, password, idNumber, address, bar, etc. I.e., the different user types require different fields.

Both frontends are protected by login pages. Since both SPAs are on the same domain as the API, I will be using sanctum's SPA auth for both, which is just cookie-based session authentication. The Laravel documentation uses the default web guard in all auth examples, which uses the default User model that comes with Laravel.

So I have (to my knowledge) 2 options:

  1. Don't mess with how sanctum is used in the docs and just use the User model for all SPA auth. To do this, I would add a type field to User (where the type can be 'admin' or 'client') and then check the type upon authentication. I.e., check that the user type is 'admin' before giving access to an admin endpoint and check that the user type is 'client' before giving access to a client endpoint. For the extra type-specific user fields, just add a foreign key to the User.id field in both AdminUser and ClientUser models.
  2. configure authentication guards and providers in config/auth.php for all the different user types. So add 'client' and 'admin' guards.

Option 1 seems easier in the sense that it is "well documented". Option 2 seems "cleaner" but has very little documentation (that I can find at least) - the docs only sort of mention that it is possible. There are forum examples out there for option 2, but all of them differ... I can't find a consistent answer.

I would greatly appreciate the advice of someone who has come across the same issue.


Solution

  • I have the same setup where there's an admin login screen (admin.test.com) and end user login screen (mypage.test.com) using Laravel sanctum and Nuxt frontend.

    I went with option 2, where I've configured multiple guards.

    auth.php

    'guards' => [
        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ],
    
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],
    
    'providers' => [
        'admins' => [
            'driver' => 'eloquent',
            'model' => \App\Models\Admin::class,
        ],
    
        'users' => [
            'driver' => 'eloquent',
            'model' => env('AUTH_MODEL', \App\Models\User::class),
        ],
    ],
    

    In your routing, you'll simply have to use the auth middleware with the guard option.

    Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
        Route::group(['middleware' => 'auth:admin'], function () {
            // Admin api endpoints
        });
    });
    
    Route::group(['prefix' => 'customer', 'as' => 'customer.'], function () {
        Route::group(['middleware' => 'auth:web'], function () {
            // User api endpoints
        });
    });