Laravel Sanctum can be use Multiauth guard

Viewed 14507

I'm testing with laravel sanctum but here some issues.. I'm creating Admin guard.

enter image description here

When I change the middleware to auth:sanctum_admin.. it should be only can access by admin but here I can access with normal user account with web guard. I don't know why?...I used passport with multiauth package.it's fine. but here in sanctum can't be separate User Table and Admin.

7 Answers

You can, also use multiple guards in sanctum. To achieve this, follow these steps -

  1. Create your own guard as required. (In config/auth.php)
'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

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

        'admin' => [
            'driver' => 'session',
            'provider' => 'admins',
        ]
    ],
  1. Set providers. (In config/auth.php)
'providers' => [
       'users' => [
           'driver' => 'eloquent',
           'model' => App\User::class,
       ],

       'admins' => [
           'driver' => 'eloquent',
           'model' => App\Admin::class,
       ],
   ],
  1. Use this guard when you authenticate a user. (In route file)
    if(auth()->guard('admin')->attempt($request->only('email','password')))
    {
        return auth()->guard('admin')->user();
    }
    

@Abhishek Mitra

and for authorizatioin using Laravel Sanctum in case of Multiple Auth Guard, we can use middleware as such

Route::middleware(['auth:guard_name'])->get('/user', function(){
    return auth()->guard('guard_name')->user();
}

config/auth.php

driver is sanctum

'guards' => [
    'users' => [
        'driver' => 'sanctum',
        'provider' => 'users',
    ],

    'partners' => [
        'driver' => 'sanctum',
        'provider' => 'partners',
    ],

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

        ],

provider:

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

    'partners' => [
        'driver' => 'eloquent',
        'model' => App\Models\Partner::class,
    ],

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

model:

must be add Authenticatable

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class Admin extends Authenticatable
{
    use HasFactory, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

Middleware:

Route::middleware(['auth:admin'])->get('/user', function(){
   
}

Guard:

auth()->guard('admin')->user();

Unauthenticated user message:

In app/Exceptions/Handler.php

use Illuminate\Auth\AuthenticationException;

function:

protected function unauthenticated($request, AuthenticationException $exception)
    {
       return response()->json(['message' => 'Unauthenticated.'], 401);

}

or

custom guard and custom redirect

public function render($request, Exception $exception)
{
    $class = get_class($exception);

    switch($class) {
        case 'Illuminate\Auth\AuthenticationException':
            $guard = array_get($exception->guards(), 0);
            switch ($guard) {
                case 'admin':
                    $login = 'admin.login';
                    break;
                default:
                    $login = 'login';
                    break;
            }

            return redirect()->route($login);
    }

    return parent::render($request, $exception);
}
  1. you must add your custom guard in config/auth.php.

'guards' => [

    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],

    'custom-guard' => [
        'driver' => 'session',
        'provider' => 'custom-provider',
    ]
],

be careful, the driver in custom guard must be session. and set provider as:

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

   'custom-provider' => [
       'driver' => 'eloquent',
       'model' => App\CustomProvider::class,
   ],

], the App\CustomProvider::class must be the model. after that can easily use the guard in auth.

auth('custom-guard')->user()

In config/auth.php:

'guards' => [
    ...

    'api' => [
        'driver' => 'sanctum',
        'provider' => 'users',
    ],
],

(Tested in Laravel 9.x)

I also face the same issue and solved it by following -

  1. In auth.php add an extra Guard - front
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'front' => [
            'driver' => 'session',
            'provider' => 'members',
        ],
    ],
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => Vanguard\User::class,
        ],

        'members' => [
             'driver' => 'eloquent',
             'model' => Vanguard\Member::class,
        ],
    ],
  1. Log in as a Default User or Member
/** Default Guard**/
if (Auth::attempt(['username' => $credentials['username'], 'password' => $credentials['password']], $request->get('remember'))) {
}
/** Front Guard **/
if (Auth::guard('front')->attempt(['username' => $credentials['username'], 'password' => $credentials['password']], $request->get('remember'))) {
}

  1. Finally add the Guard in sanctum.php
'guard' => ['front','web']

I think the default guard should be like this:

'defaults'{
    'guard' : "sanctum_admin",
    'passwords': 'admins',
}

Or

'defaults'{
    'guard' : 'web',
    'passwords' : 'users',
}
Related