JWTRefreshTokenBundle icon indicating copy to clipboard operation
JWTRefreshTokenBundle copied to clipboard

TTL_update broken?

Open geoffroyp opened this issue 2 years ago • 5 comments

Greetings,

I'm new to this library and I possibly have misunderstood the use of ttl_update option.

What I am trying to achieve is the following:

  • I'm logging in at 7.00 am. I get a JWT token that is valid until to 7.30 am, and a refresh token that is valid until 8.00 am
  • At 7.30, I'm requesting a new JWT token by using the "refresh" API endpoint and the refresh token
  • Since I have used the "single_use" option, my current refresh token is removed from DB, and I get a new one (as well as a JWT token)

...but here's the problem. What I would like, if to get a new refresh token that is valid until 8.00am, like the first one. But when I'm trying it, I get a new refresh token that is valid until 8.30 am. I've tried setting ttl_update to true and false, and both gave me the same result. I though that was the purpose of the ttl_update option: to create new refresh token that keep the same validation than the one issued during the "real" login process. Is it me who did not understand its real purpose? Is there a way to achieve such a behaviour?

Bonus questions:

  • everytime I log in, the bundle create a new refresh token. Is there a way to make sure you can get only one per user?
  • Expired token are never removed from DB. I could create a command launched by crontab to "clean" the DB table, but I was wondering there may already be an option in this package for this, otherwise the table would quickly become huuuuge and full of useless entries

Thanks!

geoffroyp avatar Apr 22 '22 08:04 geoffroyp

If you're using the single use option, then the TTL update option really doesn't matter because once a single use token is used, it's destroyed.

With TTL update and not having single use tokens, the TTL would refresh based on the time of that refresh request. With single use, the TTL is always based on the time the refresh token is created. So if your refresh token TTL is 1 hour, you've logged in at 7:00 AM, and you refresh your token at 7:35 AM, then the refresh token's TTL would be reset to 8:35 AM. It would kind of defeat the point of using refresh tokens if you got a new one and it kept the TTL of the one it's replacing. Building off the previous example, if you refresh at 7:35 AM then your JWT would be valid until 8:05 AM and the refresh token should be valid until 8:35 AM, but if the old TTL was kept and the refresh token still expired at 8:00 AM, what would happen after 8:05 AM when both the JWT and the refresh token are expired?

everytime I log in, the bundle create a new refresh token. Is there a way to make sure you can get only one per user?

You can use domain logic hooking the events from this bundle, the LexikJWTAuthenticationBundle, or the events from the security component to handle this in your application.

Expired token are never removed from DB. I could create a command launched by crontab to "clean" the DB table, but I was wondering there may already be an option in this package for this

Yep, see this section in the README.

mbabker avatar Apr 24 '22 19:04 mbabker

Thank you for your answer. I think I don't really get what the TTL_update is for, then.

To answer your question, when both the JWT and refresh token are expired, then you simply have to log in again with your credentials. That's actually what I'm trying to achieve: provide a refresh token so I can set a short expiration date for my JWT token (this way it's less problematic if someone manage to "steal" the JWT of a user), while having a refrehs token with a longer expiration, so users only have to lre-authenticate with their credentials every week or such.

But right now, single_use or not, everytime I request for a new JWT token, the bundle also create and add to the response a new refresh token with a new TTL. This way, it means the user can be logged "forever". And thus, if someone manage to steal a refresh token, he can also stay connected to our application forever. Which sounds pretty dangerous to me!

geoffroyp avatar Apr 28 '22 07:04 geoffroyp

So disable the ttl_update and single_use options and that’ll get you what you’re looking for.

mbabker avatar Apr 28 '22 12:04 mbabker

I was about to tell you that it doesn't work because the refresh_token_expiration key set in the response when using the return_expiration: true keep getting updated, but after checking my DB I noticed that the expiration remained indeed the same.

My understanding of the refresh_token_expiration was that it was returning in response the expiration date of the refresh token as unix timestamp. So, if I'm correct, then there is probably a bug there.

geoffroyp avatar Apr 28 '22 14:04 geoffroyp

Yeah, this line looks incorrect. It should probably be $refreshToken->getValid()->getTimestamp() to use the expiration time from the token instead of calculating it on each request.

mbabker avatar Apr 28 '22 15:04 mbabker