Laravel Passport - Multiple guards issue - php

Thank you in advance,
I want multiple laravel passport guards as my system has 2 user types, 1) Admin, 2) Normal User.
for both, I have separate routes and authentication modules(Login, register, logout, etc). so I need a separate passport guard for the API authentication. a few of the codes I added as below
config/auth.php looks like below
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
'api-admin' => [
'driver' => 'passport',
'provider' => 'admins',
'hash' => false,
]
],
Here i defined 2 guards for admin and user
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'table' => App\Models\Admin::class,
],
],
Here i defined 2 providers for admin and user
Now i am creating token like
$tokenResult = $user->createToken('TOKEN_DEMO');
$token = $tokenResult->token;
$token->save();
$accessToken = $tokenResult->accessToken;
It is generating well as expected for admin user with user_id = 1 (As an example consider user_id = 1)
this is about generating token for the admin user
the same way normal user logged in and generating token as same as above then this will also generate the token for the user with user_id = 1 in oauth_clients table
The table looks like as mentioned in the screenshot
The concern is that if the normal user logged out then automatically admin user's token will be destroyed as both's user_id is 1 in oauth_clients table while guards is different for both
Please help me out for the same

It's also a security issue as your user with same id as admin can pass admin authentication middleware.
Following method is the cleanest workaround I've found.
You have to use different clients for your guards.
You have to run
passport:install
two times if you have two guards using Passport. it will generate two clients.
In new versions of Passport(I think after release of Laravel 8) when you are creating a client it asks you for a provider(Defined in auth.providers config). Each provider needs one client. If you are using old versions you can manually assign providers in oauth_clients table.
Now when generating token you have to specify client id.
In older versions you could do this by changing a public property of one of Passport classes but now you should register ClientRepository again.
App::clearResolvedInstance(ClientRepository::class);
app()->singleton(ClientRepository::class, function () {
return new ClientRepository(User::CLIENT_ID, null); // You should give the client id in the first parameter
});
$token = $user->createToken('TOKEN-EXAMPLE');
$accessToken = $token->accessToken;
Now if you check your access tokens table you can see that client ids are different.
Everything is fine now.
You mentioned there might be an issue with revoking tokens but I believe even in your case(using same client and not specifying providers) if you revoke a user token with same id as admin, admin's token will still remain. Revoking user token:
$user = Auth::guard('user-api')->user();
$user->token()->revoke();

does the guard apear anywhere on the token? or do tokens only have scopes? and if so, why would you use guards when you can use scopes...
good day!
[Edit]
in my case, im using roles and permissions to write my scopes... roles and permissions are guard based and a permission or role with a admin guard cannot be assigned to a user unless we add the 'admin' key with (in my case) 'passport' drive and 'user' provider...

Related

Which middleware I should use for HomeController since I'm using Passport

I'm working on a small project using Laravel / VueJS, I'm using Passport for Authentication.
I have three pages: Login, Register, HomeController
My Question is since now I'm using Passport to login ( Token ), which middleware I should use for HomeController? I tried to use:
public function __construct()
{
$this->middleware('auth:api');
}
but it didn't work since I'm sending the Bearer token using Postman just for test.
HomeController contains a static view with no dynamic data, but I want to protect it, so that only logged users can see it.
in your application's config/auth.php configuration file the driver should be set to passport :
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
reference: https://laravel.com/docs/8.x/passport#installation
as for the middleware, it stays the same : auth:api

Set Default Guard After Register/Login When Using Multiple Guards in Laravel

I am working on a Laravel API project where the user's table has a column of type with a value of either student or company.
For the purpose of authenticating the users of both types and restricting access to certain routes, I have set up two guards with the same driver (JWT) and provider (Users).
'company' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false,
],
'student' => [
'driver' => 'jwt',
'provider' => 'users',
'hash' => false,
],
In the login and register method of my controller, I am accessing the value of user type from the form where the user selects his role (student or company).
public function register(){
$user= $this->create(request()->all());
$token=auth(request('type'))->login($user);
return $this->respondWithToken($token);
}
The purpose to access the user type is to pass that value to the auth() method which in turn uses it to log in the user through that specific guard.
The issue is: I have to use that request(type) in every controller method wherever authentication is necessary and there is need to use use the auth() related methods. e.g jwt respondwithtoken() method
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth(request('type'))->factory()->getTTL() * 60
]);
}
What I want: I want a mechanism to set the guard dynamically after the user has successfully logged in and I should able be to use the auth() method without passing any argument to it.
// shoulduseguarddynamically(request('type'));
P.S: Please also verify that using guards in this way when I have single table with multi-type users is the right approach?
First off, your approach is not really safe - just tampering with the 'type' will grant you access to places you are not supposed to go.
You would be better using Gates instead of guards for this,
You can check them in the docs here: https://laravel.com/docs/7.x/authorization#gates

Separate authentication for front-end user and admin in cakephp 3.x

We are working on a project where are 4 roles. But in cakephp 3.x Auth component holds authenticate user data in session with Auth.User indexing using
$this->Auth->setUser($user);
Due to this we are not able to access front-end user account from admin panel for some purpose, because of when we login to front-end user from admin panel, front-end login action performs and over write of session value.
So if there is any process to handle this please suggest us.
Thank you in advance.
As well I have understood that you are not using prefix to manage back-end and front-end user then may be you worked with separate folder structure for back-end, May I right?
You are right that $this->Auth->setUser($user); always holds session with Auth.User indexing. So you need to write different session indexing for back-end, and you can do it as follow :
For back-end user authentication :
**
$this->loadComponent('Auth', [
'authorize' => ['Controller'], // Added this line
'loginRedirect' => [
'controller' => 'Users',
'action' => 'dashboard',
'prefix' => 'admin_panel'
],
'logoutRedirect' => [
'controller' => 'Users',
'action' => 'login',
'prefix' => 'admin_panel'
],
'storage' => [
'className' => 'Session',
'key' => 'Auth.Admin',
]
]);
**
Here you can pass your desired index in 'storage' array key value.
I think it'll works for you.
Check out the section Authentication and Authorization in this curated list of CakePHP Plugins.
You could, for example, use dereuromarks TinyAuth Plugin to authorize your users and configure what they are able to see.
This way you can use the same authentication (be aware of the differences between Authentication and Authorization) and the same users table, which will prevent the Session conflict you mentioned.
The Auth component overwrite the previous session because it store the session in Auth.users all the time so we have to change the session key for different role.
If you are using URL prefix for the different roles to access then you can do like this.
AppController.php
public function beforeFilter(Event $event)
{
if($this->request->params['prefix']){
$this->Auth->config('storage', [
'key'=>'Auth.'.$this->request->params['prefix'],
'className'=>'Session'
]);
}
return parent::beforeFilter($event); // TODO: Change the autogenerated stub
}
This will create different roles in Auth as you required.
The session will be like this
[
'Auth'=>[
'User'=>['id'=>''],
'Admin'=>['id'=>''],
]
]
Tested it, working great for me.

how to specify more than one authenticated guard in laravel

i'm reading in Authentication section in laravel website https://laravel.com/docs/5.2/authentication
can anyone explain how I can do this , like the documentation explains , to specify separate tables for authentication ... i will quotes from laravel like below :
Accessing Specific Guard Instances
You may specify which guard instance you would like to utilize using
the guard method on the Auth facade. This allows you to manage
authentication for separate parts of your application using entirely
separate authenticatable models or user tables.
The guard name passed to the guard method should correspond to one of
the guards configured in your auth.php configuration file:
if (Auth::guard('admin')->attempt($credentials)) {
//
}
You kinda have to read the examples of adding custom guards and providers, the configuration part of it mainly. You can use the same auth 'driver', you just want to adjust what model is used by the Auth user provider.
config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
// add another one
// use the same driver, 'session', but a different user provider
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// add a provider using Eloquent but using a different model
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
]
Then you should be able to specify the guard admin to Auth. As long as that Admin model implements Authenticatable and you are passing the appropriate credentials to attempt on Auth you should be good.
If you have more middlewares and you want to apply more than one guard and by this i mean middleware you can do this in any Middleware.php file:
public function handle($request, Closure $next)
{
// if a user is Agency or Admin, let him through
if (Auth::user()->isAgency() || Auth::user()->isAdmin()) {
return $next($request);
}
// else show error page
abort(403);
}

How to use laravel's Auth class in different table?

I created a simple login and registration in my page and I also added some new columns in the default users table. Now my problem is I have another table named as admin and the default Laravel's Auth table is users. How can I implement the same functionality in my table?
In the Users model it has the declaration for the table name
protected $table = 'users';
Can you give me an example how can I use the default laravel's auth class?
Thats all thanks. :-)
Laravel takes default users table for an application. For a change of laravel authentication different table relevant table name, we need to make a small change in authentication file of config.
Go to
config/auth.php
'providers' => [
// 'users' => [
// 'driver' => 'eloquent',
// 'model' => App\User::class,
// ],
'users' => [
'driver' => 'database',
'table' => 'user',
],
],
Do you hear about Multiauth in laravel. in this library there are two or more type user can login in one laravel application. In our case there are two type user Admin and Public that means User right.
Both forgot password and reset password functionality works separately in one application.
After install this library have have one step like below.
'multi' => [ 'admin' => [ 'driver' => 'database', 'table' => 'admin', 'email' => 'client.emails.password' ], 'users' => [ 'driver' => 'database', 'table' => 'users', 'email' => 'client.emails.password', ] ],
change your Auth.php file code with this one.
installation
Firstly you want to include this package in your composer.json file.
"require": {
"sboo/multiauth" : "4.0.*"
}
Now you'll want to update or install via composer.
composer update
Usage
Everything is done the exact same way as the original library, the one exception being that all method calls are prefixed with the key (account or user in the above examples) as a method itself.
Auth::admin()->attempt(array(
'email' => $attributes['email'],
'password' => $attributes['password'],
));
Auth::client()->attempt(array(
'email' => $attributes['email'],
'password' => $attributes['password'],
));
Auth::admin()->check();
Auth::client()->check();
Here is your library
I don't think the best way is to duplicate your table. I would extend users table with a role field that indicates if the user is a standard one or an admin. This way, you can keep the same code and add the ADMIN functionality that you are looking for.
If you NEED to do that and you are using Laravel 4, maybe you can use this plugin:
https://github.com/ollieread/multiauth/
Also in this thread you have code that implements Auth in different tables:
https://gist.github.com/danielcoimbra/64b779b4d9e522bc3373
But I strongly suggest to integrate both tables in one with an Admin flag/field

Categories