Hammerbot
Hammerbot

Reputation: 16344

Laravel Passport, multiple connexions via password client

I am having troubles understanding how could I implement multiple connexions for same user via password client with Laravel Passport:

I have a mobile app, that needs to communicate with a Laravel based API. My users, at first launch of the app, will have to enter their login and password to get an access_token.

So I think that I need to put my password client secret in the code of my mobile app to be able to request tokens. But what if, my user has an iPhone and an iPad and he wants to login from both.

I'm asking because every time I make a request to POST /oauth/token, from the same password_client, every access_token of a certain user requested with my password_client gets revoked.

That would mean that, every time my user would use his iPad, he would be disconnected from his iPhone because the token wouldn't be valid anymore?

Am I missing something?

Upvotes: 2

Views: 6433

Answers (3)

Ruchita Sheth
Ruchita Sheth

Reputation: 860

I wirte below mention code in my app/Providers/AuthServiceProvider and its working. It won't removke old token and allow me login from multiple devicess

use Dusterio\LumenPassport\LumenPassport;

public function boot()
{
        $this->setPassportConfiguration();
}

private function setPassportConfiguration(): void
{
        LumenPassport::allowMultipleTokens();
}

Upvotes: 0

Ricardo Carvalho
Ricardo Carvalho

Reputation: 413

I believe that Passport changed the way it was dealing with the Access Token creation and the method @issueToken in AccessTokenController does no longer revoke old tokens (check Multiple Access Token).

I think that this change was introduced before @jesús-lozano-m answer and therefore there is no longer the need to customize controller.

However, if you want to revoke old tokens, now you can do that by setting a listener to the Passport Event AccessTokenCreated.

app/Providers/eventServiceProvider.php:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider {
    protected $listen = [
        'Laravel\Passport\Events\AccessTokenCreated' => [
            'App\Listeners\RevokeOldTokens'
        ]
    ];
    public function boot() {
        parent::boot();
    }
}

app/Listeners/RevokeOldTokens.php:

<?php

namespace App\Listeners;

use Laravel\Passport\Events\AccessTokenCreated;
use Laravel\Passport\Client;
use Carbon\Carbon;

class RevokeOldTokens {
    public function __construct() {
        //
    }
    public function handle(AccessTokenCreated $event) {
        $client = Client::find($event->clientId);
        // delete this client tokens created before one day ago:
        $client->tokens()
                  ->where('user_id', $event->userId)
                  ->where('created_at', '<', Carbon::now()->subDay())
                  ->delete();
    }
}

Upvotes: 5

Jes&#250;s Lozano M.
Jes&#250;s Lozano M.

Reputation: 46

You can write your own Controller and Routes...

Passport has a defined "Laravel\Passport\Http\Controllers\AccessTokenController" and there is a method called "issueToken()".

If you see the method below it calls the function "revokeOtherAccessTokens()", and this deletes or revoke all "access_tokens" using the "Laravel\Passport\TokenRepository"

So what you can do is to write your own controller and prevent to call "revokeOtherAccessTokens()"

The fact that you must keep in mind is that the access tokens will never be pruned or revoked at least that the refresh token became issued or manually delete them.

Refresh tokens and access tokens are revoked when refresh token is issued, because the "League\OAuth2\Server\Grant\RefreshTokenGrant" in method "respondToAccessTokenRequest()", it already revoke old "access_token" and "refresh_token", so we don't have to worry about revoke or delete them in this case.

...
// Expire old tokens
$this->accessTokenRepository->revokeAccessToken($oldRefreshToken['access_token_id']);
$this->refreshTokenRepository->revokeRefreshToken($oldRefreshToken['refresh_token_id']);
...

Here is an sample implementation, hope it helps:

routes:

Route::post('oauth/access_token', 'Auth\OAuth2Controller@issueToken');

customized controller:

<?php

namespace App\Http\Controllers\Auth;

use Laravel\Passport\Http\Controllers\HandlesOAuthErrors;

use Zend\Diactoros\Response as Psr7Response;
use Psr\Http\Message\ServerRequestInterface;
use League\OAuth2\Server\AuthorizationServer;

use App\Http\Controllers\Controller;

class OAuth2Controller extends Controller
{
    use HandlesOAuthErrors;

    /**
     * The authorization server.
     *
     * @var AuthorizationServer
     */
    protected $server;

    /**
     * Create a new controller instance.
     *
     * @param  AuthorizationServer  $server
     * @return void
     */
    public function __construct(AuthorizationServer $server)
    {
        $this->server = $server;
    }

    /**
     * Authorize a client to access the user's account.
     *
     * @param  ServerRequestInterface  $request
     * @return Response
     */
    public function issueToken(ServerRequestInterface $request)
    {
        return $this->withErrorHandling(function () use ($request) {
            return $this->server->respondToAccessTokenRequest($request, new Psr7Response);
        });
    }
}

Upvotes: 3

Related Questions