Hi I'm wondering, is it possbile to not have a TTL for refresh tokens? Because in the AbstractGrant it does the following $refreshToken->setExpiryDateTime((new \DateTime())->add($this->refreshTokenTTL)); which makes me think that if you don't set it that it will expire immediately, is that correct?
A refresh token TTL should be set otherwise it will fail this check:
if ($refreshTokenData['expire_time'] < time()) {
throw OAuthServerException::invalidRefreshToken('Token has expired');
}
@Sephster I understand, but shouldn't it be optional? Also I if I use $refreshTokenGrant->setRefreshTokenTTL(new \DateInterval("P240M")); it always throws the error you mentioned above. Is that normal or is it not allowed to set such a long interval?
I think it probably _should_ be optional. There is nothing in the spec that dictates that we should specify a TTL for the refresh token. We should probably look into rectifying this (I presume we can't do this at the moment but haven't looked into it closely enough).
There should be no problem with setting it to P240M as there is no restrictions on absolute length to my knowledge.
Great, thanks again for the help. I'll try to debug why the P240M is not working as expected.
A TTL is optional according to the spec. But using one is highly recommended. It is one of the more controversial issues with the OAuth2 spec (indefinite refresh tokens).
Systems that do allow for 'indefinite' expiration dates usually just set the expires at to something silly large like the year 2100. I think this is mostly so that one verification step can always be checking the expires at and you can count on the attributes existing in other steps.
@nealoke I was curious if I could make the expiration a fixed date (used (new DateTime)->diff(new DateTime('2100-01-01')) to create a DateInterval that spans to the year 2100) and experienced no issues with the ~81 years refresh token token age. What could however be an issue is that if you change the refresh token TTL from the default, you will need to do so for all the grants you use that can grant one (so, the authorisation code grant) and the refresh token grant itself. Or the different grants will give you new refresh tokens with different TTL.
Thank you for the further information @sg3s. I'm going to close this issue now as I believe the original question has been answered. I will open up another issue to look at the expiry time for refresh tokens
@sg3s Thanks for giving me an example for the fixed date. When I try to persist this information using the $refreshTokenEntityInterface->getExpiryDateTime()->format("Y-m-d H:i:s") it only gives me the first period though. Am I storing this incorrectly?
Example
$TTL = new DateInterval("P200M")
$refreshTokenEntityInterface->getExpiryDateTime()->format("Y-m-d H:i:s") ==> 2018/11/09 H:i:s
@nealoke That might indeed indicate that you are indeed storing it incorrectly.
The storage solution is left up to the implementer of the library, but it sounds like you might not be storing the time portion of the expiry datetime or the way you are converting the datetime from the database to a datetime (or equivalent) in php might not work correctly. It is weird how you describe that DateTime->format returns part of the format, as far as I know it should not do that.
I would suggest simplifying the problem to its core constituents and maybe posting a question on StackOverflow if you don't discover the problem yourself during that process. This is likely not a problem in the library, but if it is we'll need a much more detailed description on how to reproduce this.
@sg3s Thanks for the fast answer, the DateTime->format also returns the H:i:s elements, I just typed these as placeholders.
I checked the example and tried multiple things but I am getting quite sure that the library is not setting the TTL for refresh tokens correctly.
Setting the grant
$refreshTokenGrant = new RefreshTokenGrant($refreshTokenRepository);
$refreshTokenGrant->setRefreshTokenTTL(new \DateInterval("P240M"));
$server->enableGrantType(
$refreshTokenGrant,
new \DateInterval("PT1H")
);
RefreshTokenRepository implements RefreshTokenRepositoryInterface
public function persistNewRefreshToken(RefreshTokenEntityInterface $refreshTokenEntityInterface) {
global $db;
$db->insert("oauth_refresh_tokens", [
"id" => $refreshTokenEntityInterface->getIdentifier(),
"accessToken" => $refreshTokenEntityInterface->getAccessToken()->getIdentifier(),
"expiresAt" => $refreshTokenEntityInterface->getExpiryDateTime()->format("Y-m-d H:i:s")
]);
}
Eventhough I set the TTL with $refreshTokenGrant->setRefreshTokenTTL(...) it still chooses the default which is set in the __construct() of the RefreshTokenGrant. Normally it should overide this with the method supplied by the parent AbstractGrant but for some reason it is not the case.
With the given configuration
When your initial refresh tokens are created with the AuthCodeGrant you will need to set the TTL for those refresh tokens separately.
i.e.
$authCodeTTL = new \DateInterval('PT10M'); // 10 minutes
$refreshTTL = new \DateInterval("P240M"); // 20 years
$tokenTTL = new \DateInterval("PT1H"); // 1 hour; library default
$authCodeGrant = new AuthCodeGrant($authCodeRepository, $refreshTokenRepository, authCodeTTL);
$authCodeGrant->setRefreshTokenTTL($refreshTTL);
$refreshTokenGrant = new RefreshTokenGrant($refreshTokenRepository);
$refreshTokenGrant->setRefreshTokenTTL($refreshTTL);
$server->enableGrantType($refreshTokenGrant, $tokenTTL);
$server->enableGrantType($authCodeGrant, $tokenTTL);
If you do not use the $authCodeGrant->setRefreshTokenTTL($refreshTTL); the refresh tokens created during an AuthCodeGrant will have the default expiry time.
I agree that this is a confusing implementation detail. I tried explaining this in my response 20 days ago too ;)
@sg3s omg, didn't understand that at all 馃槃. Thanks for the effort and speed of answering my question!
THANK YOU