3
votes

I've multiple guards in my laravel application:

Code config/auth.php:

'defaults' => [
    'guard' => 'user',
    'passwords' => 'users',
],

'guards' => [
    'user' => [
        'driver' => 'token',
        'provider' => 'users',
        'hash' => true,
    ],
    'admin' => [
        'driver' => 'token',
        'provider' => 'admins',
        'hash' => true,
    ]
],

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => User::class,
    ],
    'admins' => [
        'driver' => 'eloquent',
        'model' => Admin::class,
    ],
],

'passwords' => [
    'users' => [
        'provider' => 'users',
        'table' => 'users_password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
    'admins' => [
        'provider' => 'admins',
        'table' => 'admins_password_resets',
        'expire' => 60,
        'throttle' => 60,
    ],
],

'password_timeout' => 10800,

And has route for get authenticated user in api.php:

Route::get('admins/auth/user', 'AuthController@user')->middleware('auth:sanctum');

Also in my models (Admin, User) used trait:

Laravel\Sanctum\HasApiTokens

When I tried get auth user by token get error with message:

InvalidArgumentException: Auth guard [web] is not defined. in file appname\vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php on line 84

#0 appname\vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php(68): Illuminate\Auth\AuthManager->resolve()
#1 appname\vendor\laravel\sanctum\src\Guard.php(45): Illuminate\Auth\AuthManager->guard()
#2 [internal function]: Laravel\Sanctum\Guard->__invoke()
#3 appname\vendor\laravel\framework\src\Illuminate\Auth\RequestGuard.php(58): call_user_func()
#4 appname\vendor\laravel\framework\src\Illuminate\Auth\GuardHelpers.php(60): Illuminate\Auth\RequestGuard->user()
#5 appname\vendor\laravel\framework\src\Illuminate\Auth\Middleware\Authenticate.php(63): Illuminate\Auth\RequestGuard->check()
#6 appname\vendor\laravel\framework\src\Illuminate\Auth\Middleware\Authenticate.php(42): Illuminate\Auth\Middleware\Authenticate->authenticate()

I've runned already commands:

php artisan cache:clear
php artisan config:cache

And also tried add guard name to config/sanctum.php:

'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),

'expiration' => null,

'middleware' => [
    'verify_csrf_token' => App\Http\Middleware\VerifyCsrfToken::class,
    'encrypt_cookies' => App\Http\Middleware\EncryptCookies::class,
],

// This line added
'guard' => 'admin'
2

2 Answers

1
votes

For me, adding the guard in the config/sanctum.php file solved my issue.

'guard' => 'admin'

You can see here how the config is being used by sanctum's guard here.

https://github.com/laravel/sanctum/blob/2.x/src/Guard.php#L55

You can also pass an array of values according to the code above since the config is wrapped by Arr::wrap

0
votes

I solved something similar, since I use authentication for USERS and ADMINS users. You can use sanctum to authenticate yourself with the laravel / ui package using middleware ('auth: sanctum') but to get this to use an ADMIN model and not USER, you have to change the guard. Let me explain: sanctum is normally a guard defined in auth, as are 'web' and 'api', which happens that by default the auth.guards.sanctum has the provider = null. So what I did was define my own guard:

'providers' => [
'admin' => [
            'driver' => 'sanctum',
            'provider' => 'admins',
        ],
],

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

and you can protect your routes with middleware ('auth: sanctum') and in this way you are using the Admin model and not the User model. Every time a route is called that is within the group that you are protecting with auth: sanctum this auth.guard is binding the to providers.admins and this will always verify the Admin model.

The problem you are going to have is when you login, you have to define which guard you are going to use when you login, since if you use the laravel / ui package, it is by default using guards. web and this will associate the User model, and although there is a user with the same credentials in the User model, when he accesses the paths protected with sanctum, he will verify the credentials with the Admin model. So the trick is, at the time of login, to force the change of the guard to one that has the provider Admin. In my case what I did was create a middleware that what it does is change the provider of the guards.web Create the middleware, I registered it in the kernel.php file in the routeMiddleware and put it like this:

'auth.admin' => \ App \ Http \ Middleware \ AuthenticateGuardAdmin :: class,

and the middleware contains inside this line of code: Config :: set ('auth.guards.web.provider', 'admins');

And the middleware I put it here:

Route :: middleware ('auth.admin') -> group (function () {
    Auth :: routes (['register' => false]);
    Route :: middleware ('auth: sanctum') -> group (function () {
        Route :: get ('/ home', 'HomeController @ index') -> name ('home');
    });
});

At the time of login with the standard controllers that use the laravel / ui package, I am already telling the configuration variables that the provider that will be used will be the one that I have defined that uses the Admin model. And with this, the login, authentication and authorization are always done with the Admin model.

Afterwards you can create other groups of routes even with other authentication definitions and with other models or the same default User model, using even the sanctum in the API routes or in the web routes.