Can we use laravel passport with different guards to authenticate APIs for two different types of users. For example we have driver app for driver user and vendor app for vendor user. Both have their different models Driver and Vendor. How can we use different guards to authenticate both types of users using Laravel Passport?
I managed to create multiple auths (with laravel/passport) by using a simple middlware.
Step 1: config/auth.php
Add your user classes to providers
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'basic_users', // default
],
],
...
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'admin_users' => [
'driver' => 'eloquent',
'model' => App\AdminUser::class,
],
'basic_users' => [
'driver' => 'eloquent',
'model' => App\BasicUser::class,
],
],
Clean the cache via CLI
php artisan config:cache
Step 2: Create middleware
php artisan make:middleware AdminUserProvider
Open the newly created middleware in app/Http/Middleware and update the hand method like below
public function handle($request, Closure $next)
{
config(['auth.guards.api.provider' => 'admin_users']);
return $next($request);
}
Step 3: Register your middleware
Add the newly created middleware to $routeMiddleware
protected $routeMiddleware = [
...
'auth.admin' => \App\Http\Middleware\AdminUserProvider::class,
];
and make sure it's at the top of $middlewarePriority
protected $middlewarePriority = [
\App\Http\Middleware\AdminUserProvider::class,
...
];
Step 4: Add middleware to route
Route::group(['middleware' => ['auth.admin','auth:api']], function() {
Step 5: LoginControllers (AdminUserController & BasicUserController)
public function login()
{
$validatedData = request()->validate([
'email' => 'required',
'password' => 'required|min:6'
]);
// get user object
$user = AdminUser::where('email', request()->email)->first();
// do the passwords match?
if (!Hash::check(request()->password, $user->password)) {
// no they don't
return response()->json(['error' => 'Unauthorized'], 401);
}
// log the user in (needed for future requests)
Auth::login($user);
// get new token
$tokenResult = $user->createToken($this->tokenName);
// return token in json response
return response()->json(['success' => ['token' => $tokenResult->accessToken]], 200);
}
In summary:
The login controllers use Eloquent models to get the user object and then log the user in through Auth::login($user)
Then for future requests that need authentication, the new middleware will change the api auth guard provider to the correct class.
Edit: Passport now has support for multiple guard user providers. Please refer the following links for more infos:
Multiple Authentication Guards
Old answer (I would not recommend it)
Here is an example of auth.php and api.php to start with
config/auth.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'driver-api' => [
'driver' => 'passport',
'provider' => 'drivers',
],
'vendor-api' => [
'driver' => 'passport',
'provider' => 'vendors',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'drivers' => [
'driver' => 'eloquent',
'model' => App\Driver::class,
],
'vendors' => [
'driver' => 'eloquent',
'model' => App\Vendor::class,
],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
],
'drivers' => [
'provider' => 'drivers',
'table' => 'password_resets',
'expire' => 60,
],
'vendors' => [
'provider' => 'vendors',
'table' => 'password_resets',
'expire' => 60,
],
],
];
routes/api.php
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
*/
Route::group(['namespace' => 'Driver', 'prefix' => 'driver/v1', 'middleware' => 'auth:driver-api'], function() {
// define your routes here for the "drivers"
});
Route::group(['namespace' => 'Vendor', 'prefix' => 'vendor/v1', 'middleware' => 'auth:vendor-api'], function() {
// define your routes here for the "vendors"
});
You have to modify this files:
File: vendor\laravel\passport\src\Bridge\UserRepository.php
Copy/Paste getUserEntityByUserCredentials to make a duplicate of it and name it getEntityByUserCredentials
Then, in the new duplicated function, find the below:
$provider = config('auth.guards.api.provider');
And Replace it with:
$provider = config('auth.guards.'.$provider.'.provider');
File: vendor\league\oauth2-server\src\Grant\PasswordGrant.php
in : validateUser method add after $username and $password :
$customProvider = $this->getRequestParameter('customProvider', $request);
if (is_null($customProvider)) {
throw OAuthServerException::invalidRequest('customProvider');
}
And this instead of the original line
$user = $this->userRepository->getEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client,
$customProvider
);
After doing this you'll be able to pass an extra key/value pair to your access token request, like for example:
grant_type => password,
client_id => someclientid
client_secret => somesecret,
username => someuser,
password => somepass,
client_scope => *,
provider => driver-api // Or vendor-api
I hope this will be helpful for you
After spent time I have found that in Laravel 7 there is no custom code required except some configuration. For details please check this answer I have tested & implemented in my projects Multi Auth with Laravel 5.4 and Passport
You don't necessarily need to change config for each request. You need a client for each guard. After creating clients by running
passport:install
Make sure you specified provider field in database. It should be same value as auth.providers config.
After creating clients and guards, use following code when creating an access token.
App::clearResolvedInstance(ClientRepository::class);
app()->singleton(ClientRepository::class, function () {
return new ClientRepository(User::CLIENT_ID, null); // Client id of the model
});
Make sure you specified provider in oauth_clients table.
© 2022 - 2024 — McMap. All rights reserved.