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

Clarification on Refresh Token Behaviour #2241

Open
eznix86 opened this issue Feb 28, 2024 · 9 comments
Open

Clarification on Refresh Token Behaviour #2241

eznix86 opened this issue Feb 28, 2024 · 9 comments

Comments

@eznix86
Copy link

eznix86 commented Feb 28, 2024

Clarify JWT Token Behaviour

Explanation

The tymondesigns/jwt-auth access token has an hybrid behaviour. It can be used as a refresh token and as an access token. Once it has passed the expiration time in minutes, It will be invalid as an access token but it will still be valid as a refresh token. When the token is refreshed, the token sent is invalidated (means you cannot use it anymore) and a new token is returned. So once you call ->refresh() it will invalidate the JWT token previously generated.

Exclude refresh in middleware

Endpoint which has a refresh behavoir should not be using the middleware 'auth:api'. Example:

$this->middleware('auth:api')->except(['refresh']);

or do not include it in a group route middleware.

Behavior: Only call refresh() when you need to refresh.

if you want a behaviour where the JSON has a refresh and a access_token, generate a token, then use same for both.

$token = auth()->attempt($credentials); // or ->login($user);
//...
// DO NOT CALL `->refresh()` else it will invalidate the access token.
return [
   "access_token" => $token, 
   "refresh_token" => $token
];

Configuration is for the SAME token

The ttl and refresh_ttl in the jwt.php config is for the same token.

Thanks to:
#2219

Fixes:
#2116
#2209
#2205
#2201
#2149
#2136
#2116
and maybe more ....

@tymondesigns to close all those issues and add this to the docs.

@eznix86 eznix86 changed the title Clarify Refresh Token Behaviour Clarification on Refresh Token Behaviour Feb 28, 2024
@designermonkey
Copy link

designermonkey commented Mar 20, 2024

I think you're going to need to make a more precise explanation of this as it does not make sense. How are you supposed to utilise the refresh_token you describe above? none of the docs show that token being put into use, and I can't see any actually useful examples on how you would use the refresh_token.

Say we use a jwt ttl of 1 minute, and a refresh ttl of 15 minutes, irrespective of whether we successfully refresh our access, we are unauthenticated after the 15 minute window from the original issued time. Surely, a refresh should change the refresh window to a new issued time plus the 15 minutes? Whatever we do the issued time never changes.

@eznix86
Copy link
Author

eznix86 commented Mar 20, 2024

I think you're going to need to make a more precise explanation of this as it does not make sense. How are you supposed to utilise the refresh_token you describe above? none of the docs show that token being put into use, and I can't see any actually useful examples on how you would use the refresh_token.

Say we use a jwt ttl of 1 minute, and a refresh ttl of 15 minutes, irrespective of whether we successfully refresh our access, we are unauthenticated after the 15 minute window from the original issued time. Surely, a refresh should change the refresh window to a new issued time plus the 15 minutes? Whatever we do the issued time never changes.

Glad you ask. I am not creating the feature here, I am just describing what happens, as you saw there are a lot of issues opened exactly because of that. Too much even! So it attest that this is an issue rather than the normal behaviour of a refresh token you just described.

TLDR; The issue is here, and my explanation is above is to help people who had the same issue as I had (same for the other long list of issues that has been opened).

PS. Try the package, make a refresh token, and an access token. After trying the package you will understand what is going on!

@designermonkey
Copy link

designermonkey commented Mar 20, 2024

Thanks for your reply, I thought you were describing the solution, not just gathering up the problems. Sorry if I came across rude.

We have the package in place, and issues were raised with us via a PEN test, so we have stumbled upon this not working as expected.

My expected behaviour is that there shouldn't be any kind of physical refresh token at all, that is an OAuth2 thing, not a JWT thing. I would expect though that the refresh TTL exists and is used properly.

  • When a url is visited and token is still valid, no action is taken.
  • When a url is visited and a token is invalid, take the token iat + refresh_ttl
    • if it is still a valid timestamp, issue a new token, with a new iat
    • if it is not a valid timestamp, expire the token, thus causing a new login.

The problem I see is that the iat never changes in the token, so it will always expire at the refresh_ttl time irrespective. That makes this quite a simple bug to fix IMO.

@designermonkey
Copy link

'iat' => $payload['iat'],

This line is incorrect, as far as I can see. A refreshed token should always receive a new iat.

@eznix86
Copy link
Author

eznix86 commented Mar 20, 2024

Unfortunately the maintainer is not here for unknown reasons.

I would recommend to fork the repo and fix the issues.

That's why also I open the issue because the maintainer is not anymore present on this package. No one can merge fixes to existing issues 😕.

I even email the maintainer. No reply.

@amos-yau
Copy link

amos-yau commented May 13, 2024

@eznix86 did you fork it and fixed? I encountered the same issue, this is really a bug that the 'iat' is not refreshing, so the new token will be expired and unable to be refreshed if it's 'exp' passed/hit the origin 'refresh_ttl' (hope my understanding to the TTL and REFERSH_TTL is correct)

The bug with a fixed 'iat':

token 1          :      |iat|       |exp|                           |refresh_ttl|
token 1-refreshed:      |iat|              |exp|                    |refresh_ttl|
token 1-refreshed:      |iat|                     |exp|             |refresh_ttl|
...
token 1-refreshed:      |iat|                                  |exp||refresh_ttl| <<< user must be kicked out

My understanding, so user won't be kicked out if he keep refreshing the token:

token 1          :      |iat|       |exp|                    |refresh_ttl|
token 1-refreshed:             |iat|       |exp|                    |refresh_ttl|
token 1-refreshed:                    |iat|       |exp|                    |refresh_ttl|

@designermonkey is this aligned to your view too?

@eznix86
Copy link
Author

eznix86 commented May 13, 2024

@eznix86 did you fork it and fixed? I encountered the same issue, this is really a bug that the 'iat' is not refreshing, so the new token will be expired and unable to be refreshed if it's 'exp' passed/hit the origin 'refresh_ttl' (hope my understanding to the TTL and REFERSH_TTL is correct)

The bug with a fixed 'iat':

token 1          :      |iat|       |exp|                           |refresh_ttl|
token 1-refreshed:      |iat|              |exp|                    |refresh_ttl|
token 1-refreshed:      |iat|                     |exp|             |refresh_ttl|
...
token 1-refreshed:      |iat|                                  |exp||refresh_ttl| <<< user must be kicked out

My understanding, so user won't be kicked out if he keep refreshing the token:

token 1          :      |iat|       |exp|                    |refresh_ttl|
token 1-refreshed:             |iat|       |exp|                    |refresh_ttl|
token 1-refreshed:                    |iat|       |exp|                    |refresh_ttl|

@designermonkey is this aligned to your view too?

Lol, no, the maintainer does not respond anymore. Basically just follow the thing I explained earlier you should be good, either you abide by it or find another package.

@eznix86
Copy link
Author

eznix86 commented Jun 18, 2024

I believe due to the absence of the maintainer. Use Laravel Sanctum instead.

Documentation of Laravel Sanctum:
https://laravel.com/docs/11.x/sanctum#issuing-api-tokens

Note: Sanctum creates only a token which can be reused.

To perform access and refresh token behaviour I would recommend to look at:
https://medium.com/@marcboko.uriel/manage-refresh-token-and-acces-token-with-laravel-sanctum-85defbce46ed
https://muhamadhhassan.me/creating-refresh-tokens-with-laravel-sanctum

Note: I am not the author of those posts.

@specialtactics
Copy link

specialtactics commented Jul 25, 2024

Hey guys, there is already a fork of this repo which has been maintained for quite some time, and continues to be.

https://github.com/PHP-Open-Source-Saver/jwt-auth

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