Search code examples
phpoauthlaravel-passport

Laravel Passport - Multiple guards issue


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 enter image description here

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


Solution

  • 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. enter image description here 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();