bshaffer / oauth2-server-php

A library for implementing an OAuth2 Server in php
http://bshaffer.github.io/oauth2-server-php-docs
MIT License
3.26k stars 950 forks source link

refresh_token and invalid_grant response #986

Open Aymkdn opened 4 years ago

Aymkdn commented 4 years ago

Hi,

I'm using PDO as a storage method. I have refresh tokens that are available with the below config:

// for refresh tokens
$server->addGrantType(new OAuth2\GrantType\RefreshToken($storage, [
  'always_issue_new_refresh_token' => true,
  'unset_refresh_token_after_use'  => false
]));

I'm using OAuth2-server-php with Amazon Alexa for a skill. Alexa will send a POST to my token.php page with a "Authorization" header that contains the client_id and the client_secret, and the below body:

{"grant_type":"refresh_token","refresh_token":"3673c55124f61d8fxyz37a315bb0296de","client_id":"alexa"}

If the token is still valid, no problem. However if the refresh_token is expired Oauth2-server-php will return an error 400 with

{"error":"invalid_grant","error_description":"Refresh token has expired"}

And then… nothing. Alexa says to the user that they have to reactivate the skill!

Should the Oauth2-server-php send back a new valid token when the refresh_token is expired? Or should Alexa send a different request to the server to get a new token because the server replied with invalid_grant? Did I miss a parameter somewhere for Oauth2-server-php?

Thanks

Aymkdn commented 4 years ago

I posted this question on three different places (here, Stackoverflow, and Amazon Alexa forum), but no answer…

As a "fix" I did the below in my server.php:

$server->addGrantType(new OAuth2\GrantType\RefreshToken($storage, [
  'always_issue_new_refresh_token' => false,
  'unset_refresh_token_after_use'  => false
]));

And I changed RefreshToken.php by removing this part of the code:

if ($refreshToken['expires'] > 0 && $refreshToken["expires"] < time()) {
    $response->setError(400, 'invalid_grant', 'Refresh token has expired');
    return null;
}

Until I get a better answer/explanation :-)

lukehesluke commented 3 years ago

@Aymkdn with your settings as they were:

$server->addGrantType(new OAuth2\GrantType\RefreshToken($storage, [
  'always_issue_new_refresh_token' => true,
  'unset_refresh_token_after_use'  => false
]));

you haven't set a refresh token lifetime (unless you have?) so, your refresh token lifetime will use the default value, which is 14 days.

Is Amazon Alexa really doing a token refresh less often than once every 14 days? Once it does a token refresh, oauth2-server-php will return a new refresh token with a new 14 day lifetime (since always_issue_new_refresh_token is set to true), so if Amazon Alexa is processing this properly, it should update its internal refresh token (so that it does not use the previous refresh token which will later expire).

So I think one of the following must be happening:

  1. Amazon Alexa is doing a token refresh less often than once every 14 days.

    In which case, you might be able to inform Alexa to do it more often (I have no experience with Alexa so I don't know how this would be done). Alternatively, you could update the oauth2-server-php refresh token lifetime

  2. There's a bug in oauth2-server-php where it's either:
    • not issuing new refresh tokens (despite always_issue_new_refresh_token being set to true)
    • not honouring its refresh token lifetime
  3. There's a bug in Amazon Alexa where it's not getting the new refresh token value from the refresh_token grant (as it should do)
Aymkdn commented 3 years ago

Thanks for the reply. I did not set any refresh token lifetime (I don't know if there is a setting for that?!), and I don't know the Amazon Alexa token lifetime…

At least, it's working now for me the way I did it!