94

If I understand best practices, JWT usually has an expiration date that is short-lived (~ 15 minutes). So if I don't want my user to log in every 15 minutes, I should refresh my token every 15 minutes.

I need to maintain a valid session for 7 days (UX point of view), so I have two solutions:

  • use long-lived json web token (1 week)--bad practice?
  • getting a new json web token after the old one expires (JWT 15min, refresh allowed during 1 week)

I'm forcing the use of HTTPS.

The JWT standard doesn't speak about refreshing tokens. Is refreshing an expired token a good strategy?

7 Answers 7

62

Refreshing a token is done to confirm with the authentication service that the holder of the token still has access rights. This is needed because validation of the token happens via cryptographic means, without the need to contact the authentication service. This makes the evaluation of the tokens more efficient, but makes it impossible to retract access rights for the life of a token.

Without frequent refreshing, it is very difficult to remove access rights once they've been granted to a token. If you make the lifetime of a token a week, you will likely need to implement another means to handle, for example, the deletion of a user account, changing of a password (or other event requiring relogin), and a change in access permissions for the user.

So stick with the frequent refresh intervals. Once every 15-minutes shouldn't be enough to hurt your authentication service's performance.

Edit 18 November 2019: Per @Rishabh Poddar's comment, you should generate a new refresh token every time the old one is used. See this in-depth discussion of session management for details.

12
  • 1
    so I can refresh an expired token ? why people recommend not to ? Apr 4, 2016 at 7:12
  • 3
    Without a reference, it is hard to understand why something was recommended. Do you have references? The point of refresh token is to alllow revocation of access rights without hitting the authentication service too frequently. You can refresh the token (which does an access check) without needing to reauthenticate. Jul 11, 2017 at 3:40
  • Ok so refresh tokens can also expire but are long-lived. They are only used to do revocation of access rights. So those token can be used to refresh an expired token. Jul 11, 2017 at 10:39
  • 1
    @AliSherafat - as long as the refresh token is saved and still valid, then the app can get a new access token. If the refresh token is expired, then the user has been logged out due to being idle and will need to login again. Apr 5, 2018 at 3:33
  • 3
    To add a bit more information: The ideal method according to RFC 6819 is to keep changing refresh tokens when they are used - this provides the maximum amount of security as demonstrated in this 2-part blog post. Nov 14, 2019 at 8:49
19

You should refresh the token every 15 minutes, but you don't need to let the user authenticate again to do so.

  • After authenticating, hand out a JWT that is valid for 15 minutes.
  • Let the client refresh the token whenever it is expired. If this is done within seven days, a new JWT can be obtained without re-authenticating.
  • After a session is inactive for seven days, require authentication before handing out a new JWT token.

This way you can for example require authentication after a user changed their password.

11
  • it's the solution I use for now, Let the client refresh the token whenever it is expired. My question is : is refresh an expired token is a good strategy ? Apr 13, 2016 at 7:47
  • 13
    The client does not actually refresh the old token in the sense that it uses the old token to get a new one. Instead, the authentication layer knows the client was logged in recently and gives him a new token. You could implement this by using two JWTs, one that is valid for 15 minutes and one that is valid for 7 days. The long-running token can only be used to request a short-running token, and the short-running token can be used to access your API or whatever. This still makes it possible to revoke access every 15 minutes, while still having sessions of 7 days.
    – Sjoerd
    Apr 13, 2016 at 7:55
  • 7
    How does refreshing a token even work? Do you store the username + password of the user on the client side?
    – Roger Far
    Mar 6, 2017 at 3:24
  • 3
    Why not create a long-lived token and track it in the database for revocation? That way, deleting the token tracking token effectively invalidates and revokes the JWT token. One drawback is that on each request, you still have to go in the database to make sure the token is still being tracked. Aug 8, 2019 at 0:00
  • 2
    @TheRealChx101 The whole point of JWT tokens is to make API stateless.
    – metalim
    Mar 12, 2021 at 19:58
10

Typically for JWTs you'll have an access token, that's valid for ~15 minutes, and a refresh token that is valid for longer (e.g. 24 hours).

To access API end points, the browser sends only the access token. If it receives a 401 HTTP status, it then refreshes it's token by submitting the refresh token to a specified end point, retrieves two new tokens (both refresh and access) and continues along.

Here's the wonderful thing. Both tokens have expiry dates, both tokens are signed -- hence you should always validate all tokens (regardless of access or refresh) using the same logic, before performing token specific validation.

6

My setup is..

When someone logs in, generate a JWT with an exp of 5 days, with a custom field, useExp of 10 mins

When someone makes an authenticated request, the useExp must be in the future, unless they're asking for a new token

When someone makes an authenticated request for a new token, the useExp can be in the past, but the exp must be in the future. If valid, I'll generate them a new token as if they just logged in.

If both exp's are in the past, they must make an unauthenticated request to login with their email and password.

5
  • So each response comes with an overhead of checking for a newer token. Aug 8, 2019 at 0:05
  • 1
    I don't understand your comment. What do you mean checking for a newer token? They aren't stored anywhere server side, thats the good thing about JWT. You just take the token given in the Authentication header, check its valid and not expired. A special case would be a refresh endpoint, which would allow expired token, but check an additional field, which contains a longer expiry time, in which the token can be refreshed. In this way, the server is only comparing a timestamp against the current time, it's hardly an overhead. Aug 8, 2019 at 10:41
  • What I meant was you have no control over the jwt's use. Your method is good and all but if the token ever got stolen (somehow) there'd be no way to terminate the session because the server does not reflect its state in any way. So, what I have done before is create an id (JTI field) for tokens and store that in the database. If there's no matching JTI token in the database then the JWT is rejected regardless of whether it's expired on not. This way, I can issue JWT as old as 90 days so application users don't get annoyed to sign in. Of course this depends on the type of application. Aug 8, 2019 at 23:56
  • This gives me total control of the JWT and sessions because I can terminate a session at any given time. Your method might work well with financial and sensitive types of applications. For a chat/social application, it would be counter intuitive to ask the user to login every 5 days. I think the best way is to let the user know when there session will end and allow them to manually refresh the token say, 60 to 10 minutes before expiration. The overhead I was referring to was because I thought this refresh process was done automatically. Aug 9, 2019 at 0:05
  • 1
    one of the great things about JWT is you don't need to keep track of it on the server-side. That said, they are flexible and can be used in many different ways, so it just depends on what you want to get out of it. The scenario of wanting to limit the life of a token while not annoying them with constantly having to sign in again is the exact case a token with an expiry and a refresh expiry solves. it expires after 10 mins, at which point the app needs to make a explicit request to the server to say "can I have another token?" - at which point it might say no, because things have changed. Aug 9, 2019 at 8:18
5

You can get the access token configured for 7 days when the user authenticates. However it won't be the best practice security-wise because it would be harder to revoke access if needed. Of course it depends on your needs but the best practice is to also get the refresh token and user it to refresh the access token every period.

2
  • Everyone is talking about refresh tokens but won't show exactly how. Out of band requests? For a passive application that only pulls data from the server when interacted with, there's no way to do that unless timed, in which case you'll be facing other problems such as connectivity issues when a scheduled refresh request is attempted. Aug 8, 2019 at 0:03
  • There are a bunch of implementations out there. Depends on which framework and language you are using.. Just a few examples: auth0.com/blog/… developer.okta.com/docs/guides/refresh-tokens/use-refresh-token
    – Igliv
    Aug 11, 2019 at 10:20
5

It seems like you are utilizing JWTs for session management. What you are wrestling with is a typical issue that comes up with this authentication scheme. JWTs are not ideal for session management requirements. You need various tricks to keep the session alive for longer (like others described), to revoke rights or log out. Here is an article that outlines what trade-offs you need to face with this setup.

If you can live with the compromises, JWTs are ok for session management. Should you need more granular control, take a look at cookie-based session management schemes.

1

For those who mentioned two JWTs (@keithRozario @Sjoerd) or one JWT but two fields (@Michael Baldry @Laurens Rietveld):

Let's called the two JWT or two fields access token and refresh token.

If the hacker get the access token somehow, then it is very likely that the refresh token is also leaked and the hacker can request the access token by using the refresh token. In that sense the access token's short expiration doesn't help much here.

someone suggested that a revocation list should be maintained at the server side so every request to refresh the token should be checked. Well, one of the major reason that people use JWT is that server doesn't need to maintain the session so it's more scalable. Doesn't the idea of maintaining the revocation list break this advantage?

One way that I can think of is to add another field to the access token to restrict refreshing the token to, say 30 minutes. So it can mitigate the loss even if both access token and refresh toke are leaked. But I'm not sure whether it's a good practice or not.

2
  • 2
    Hey! A good balance here can be to have short-lived JWT access tokens and long-lived opaque (non-JWT) refresh tokens. If you need to have revocation list, you can have that just for the refresh token - so that when you use access tokens, you don't have to do a db lookup (still scalable). But when you use the refresh token (not that frequent), you can check this list. More information can be found on this blog Nov 14, 2019 at 9:20
  • 2
    AccessToken(AT) and RefreshToken(RT) wont get leaked together regardles of format used. The whole idea is that AT can be used willy-nilly attached to whatever requests to whatever sites or subsites of your infrastructure. If one of the pages will get hijacked somehow, it can then capture the token. But RT is sent to ONE and only ONE endpoint - /refresh on auth server. This way RT is more secure than AT. Also, having one token with 2 fields is obviously breaking this and should never happen.
    – HubertNNN
    Feb 16, 2021 at 13:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .