Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refresh token refreshes all the time #232

Closed
ronnievisser opened this issue Jan 4, 2017 · 4 comments
Closed

Refresh token refreshes all the time #232

ronnievisser opened this issue Jan 4, 2017 · 4 comments

Comments

@ronnievisser
Copy link

ronnievisser commented Jan 4, 2017

Hi,

I'm having an issue with refresh tokens. in mu AuthServiceProvider I have the following piece of code.

public function boot()
    {
        $this->registerPolicies();

        Passport::routes();

        Passport::tokensExpireIn(Carbon::now()->addDays(1));

        Passport::refreshTokensExpireIn(Carbon::now()->addYears(1));

        Passport::pruneRevokedTokens();

        Passport::tokensCan([
            'pain' => 'Generate PAIN files',
            'offload' => 'Offload Data',
            'camt' => 'Process CAMT files'
        ]);
    }

setting the refreshTokensExpireIn to 1 year from now as stated in the documentation. No everytime I want to refresh my access token the refresh token is also being refreshed. looking at other applications I found out that in most of the cases the refresh token never expires.

my question: What am I doing wrong? why is my refresh token refreshed all the time. and the other question, Is it possible that the refresh token never expires?

thanks in advance

@craigpaul
Copy link

craigpaul commented Jan 4, 2017

If we take a look into the underlying library for Passport (league/oauth2-server), you'll notice in the refresh grant that the refresh token always gets refreshed (look at the // Expire old tokens comment).

public function respondToAccessTokenRequest(
    ServerRequestInterface $request,
    ResponseTypeInterface $responseType,
    \DateInterval $accessTokenTTL
) {
    // Validate request
    $client = $this->validateClient($request);
    $oldRefreshToken = $this->validateOldRefreshToken($request, $client->getIdentifier());
    $scopes = $this->validateScopes($this->getRequestParameter('scope', $request));

    // If no new scopes are requested then give the access token the original session scopes
    if (count($scopes) === 0) {
        $scopes = array_map(function ($scopeId) use ($client) {
            $scope = $this->scopeRepository->getScopeEntityByIdentifier($scopeId);

            if ($scope instanceof ScopeEntityInterface === false) {
                // @codeCoverageIgnoreStart
                throw OAuthServerException::invalidScope($scopeId);
                // @codeCoverageIgnoreEnd
            }

            return $scope;
        }, $oldRefreshToken['scopes']);
    } else {
        // The OAuth spec says that a refreshed access token can have the original scopes or fewer so ensure
        // the request doesn't include any new scopes
        foreach ($scopes as $scope) {
            if (in_array($scope->getIdentifier(), $oldRefreshToken['scopes']) === false) {
                throw OAuthServerException::invalidScope($scope->getIdentifier());
            }
        }
    }

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

    // Issue and persist new tokens
    $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $oldRefreshToken['user_id'], $scopes);
    $refreshToken = $this->issueRefreshToken($accessToken);

    // Inject tokens into response
    $responseType->setAccessToken($accessToken);
    $responseType->setRefreshToken($refreshToken);

    return $responseType;
}

So in answer to your question about never expiring refresh tokens...not possible. In answer to why it's always being refreshed...that's how the library is designed to work. Just because the token last's a long time, doesn't mean it SHOULD be usable more than once, and that seems like that's how Alex interpreted that when he built it.

Basically, you aren't doing anything wrong. That's how this library (and the underlying one) operate.

@ronnievisser
Copy link
Author

ronnievisser commented Jan 5, 2017

Ok, thanks for your answer.

@djboris88
Copy link

Sorry for bumping the thread, but facing the same issue, I found the easy solution.

To simply ignore token revocations, just do this:

  1. Create a new Model which will extend Laravel\Passport\RefreshToken
  2. In app/Providers/AuthServiceProvider.php, method boot(), add Passport::useRefreshTokenModel(YourExtendingRefreshToken::class);
  3. In that model override revoked attribute accessor using getRevokedAttribute() to always return false

For my needs, I wanted to add a grace period to token revocations, in case multiple refresh token requests were sent in parallel. What I did is a bit more complicated, but still very simple:

  1. Created a new Model which will extend Laravel\Passport\RefreshToken
  2. In app/Providers/AuthServiceProvider.php, method boot(), I added Passport::useRefreshTokenModel(YourExtendingRefreshToken::class);
  3. In that model I override revoked attribute mutator and accessor using setRevokedAttribute() and getRevokedAttribute()
  4. I created a new migration to add revoked_at dateTime column
  5. In the setRevokedAttribute() mutator I also set the value of revoked_at to Carbon::now()
  6. In the getRevokedAttribute() accessor, if the revoked === true, I still return false if $this->revoked_at->diffInMinutes(Carbon::now()) < 10

@Sephster
Copy link
Contributor

Sephster commented Aug 2, 2021

This PR stops the revoking of refresh tokens. thephpleague/oauth2-server#1189

It is probably worth suggesting a PR to Passport to implement it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants