Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

BMS51's avatar
Level 1

Laravel Fortify / Sanctum Multi-guard error API.

Hello all,

I've tried to come up with a solution to use multi-guard system on Laravel with Fortify and Sanctum.

Contents of config/auth.php file :

/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/

'defaults' => [
    'guard' => 'admin',
    'passwords' => 'admins',
],

/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session", "token"
|
*/

'guards' => [
    'admin' => [
        'driver' => 'session',
        'provider' => 'admins',
    ],

    'api' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => false,
    ],
],

/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\Models\User::class,
    ],

    'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
    ],

    // 'users' => [
    //     'driver' => 'database',
    //     'table' => 'users',
    // ],
],

/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that the reset token should be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/

'passwords' => [
    'users' => [
        'provider' => 'users',
        'table' => 'password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
    'admins' => [
        'provider' => 'admins',
        'table' => 'admins_reset',
        'expire' => 60,
        'throttle' => 60,
    ],
],

/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/

'password_timeout' => 10800,

I have added 'guard' => 'api' in my config/sanctum.php:

return [
	'guard' => 'api',
...

config/Fortify.php

return [

/*
|--------------------------------------------------------------------------
| Fortify Guard
|--------------------------------------------------------------------------
|
| Here you may specify which authentication guard Fortify will use while
| authenticating users. This value should correspond with one of your
| guards that is already present in your "auth" configuration file.
|
*/

'guard' => 'admin',

/*
|--------------------------------------------------------------------------
| Fortify Password Broker
|--------------------------------------------------------------------------
|
| Here you may specify which password broker Fortify can use when a user
| is resetting their password. This configured value should match one
| of your password brokers setup in your "auth" configuration file.
|
*/

'passwords' => 'admins',



/*
|--------------------------------------------------------------------------
| Fortify Routes Middleware
|--------------------------------------------------------------------------
|
| Here you may specify which middleware Fortify will assign to the routes
| that it registers with the application. If necessary, you may change
| these middleware but typically this provided default is preferred.
|
*/

'middleware' => ['admin'],

,];

So with this config set up it actually works perfectly on the "web part" of the application. All functionality tested and passed

But when i use the API it's a different story... Everything that is not protected by auth:sanctum works as intended

routes/api.php

Route::middleware('auth:sanctum')->group(function (){
	Route::get('test', function(Request $request){
			 return response([
        'message' => 'All gravy baby'
        ], 200);
	});
});

But when i try to call the rout api/test i'm greeted with the following error:

{
    "message": "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'api_token' in 'where clause' (SQL: select * from `users` where `api_token` = 16|btvaV9nnktJD7SIYPlJSW9VbZQ3XybtRu9ZIbHQN limit 1)",
    "exception": "Illuminate\Database\QueryException",
    "file": "/Users/bart/sites/lff/vendor/laravel/framework/src/Illuminate/Database/Connection.php",
    "line": 678,
    "trace": [  ...
    ]
}

One solution out there was to change the driver from api in the config/auth.php

'guards' => [
    'admin' => [
        'driver' => 'session',
        'provider' => 'admins',
    ],

    'api' => [
        'driver' => 'sanctum', //from api to sanctum
        'provider' => 'users',
        'hash' => false,
    ],
],

Doing this the error will go away but funky sh*t will happen to the server:

When calling the url from postman, i get an error saying no response found... but my server keeps rebooting on every call... with no errors ...

Starting Laravel development server: http://127.0.0.1:8000 [Wed May 12 16:26:10 2021] Failed to listen on 127.0.0.1:8000 (reason: Address already in use) Starting Laravel development server: http://127.0.0.1:8001 [Wed May 12 16:26:11 2021] PHP 8.0.3 Development Server (http://127.0.0.1:8001) started [Wed May 12 16:26:13 2021] 127.0.0.1:61657 Accepted [Wed May 12 16:26:13 2021] 127.0.0.1:61658 Accepted [Wed May 12 16:26:13 2021] 127.0.0.1:61657 Closing [Wed May 12 16:26:14 2021] 127.0.0.1:61658 [200]: GET /favicon.ico [Wed May 12 16:26:14 2021] 127.0.0.1:61658 Closing [Wed May 12 16:27:05 2021] 127.0.0.1:61665 Accepted [Wed May 12 16:27:05 2021] 127.0.0.1:61665 Closing [Wed May 12 16:33:53 2021] 127.0.0.1:61705 Accepted Starting Laravel development server: http://127.0.0.1:8002 [Wed May 12 16:33:53 2021] PHP 8.0.3 Development Server (http://127.0.0.1:8002) started [Wed May 12 16:34:11 2021] 127.0.0.1:61712 Accepted Starting Laravel development server: http://127.0.0.1:8003 [Wed May 12 16:34:12 2021] PHP 8.0.3 Development Server (http://127.0.0.1:8003) started [Wed May 12 16:34:17 2021] 127.0.0.1:61714 Accepted Starting Laravel development server: http://127.0.0.1:8004 [Wed May 12 16:34:18 2021] PHP 8.0.3 Development Server (http://127.0.0.1:8004) started

Also cleared all app cache, route cache, config cache, ... i'm confused...

Anyone have any idea what's going on? i've searched around on the web, all fixes are before Dec. 2020 zo i think something changed to Sanctum or fortify between then and now?

I'm running Laravel 8.40.0, fortify 1.7.12, sanctum 2.10.0

    "laravel/fortify": "^1.7",
    "laravel/framework": "^8.12",
    "laravel/sanctum": "^2.10",
0 likes
3 replies
martinbean's avatar

@bartmommens I’m not sure if you’re expecting people to read the whole of your post, but why have you created multiple user models?

A user is a user. Use roles and then authorisation to determine what they can and can’t do. You don’t need to split users across multiple tables, and use multiple guards.

BMS51's avatar
Level 1

Hey Martin,

Looks like i went kind of overboard with the long post but wanted to provide as much detail as possible. (shortened it a bit took out excess info)

Roles unfortunaltely aren't enough.

Users are only allowed on the API part and Admins on the web part, but the main issue is that I will not be in controle of handling the roles and permissions. Splitting it up in database and creating multiple guards will prevent conflicts and wrongful role / permission assignments by others.

Users also have separate Roles and permission from Admins. There is even a case where users will not even be in the same database as the Admin (Requested by client). I've done a lot of research in how to fix those demands and the Separate Tables / Guards sadly are the only solution...

BMS51's avatar
BMS51
OP
Best Answer
Level 1

@martinbean Small update, this approach is not possible with sanctum in combination with forify. After a few days i stumbled upon an explaination that this is not possible to have multi auth with Fortify (unless with very heavy customisation with macro's and stuff). It's still possible but without Fortify to have multi auth...

Thank you for pointing me towards roles and permissions.

Kids... always listen to the lvl 50's

1 like

Please or to participate in this conversation.