81

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?

Anders
  • 64,406
  • 24
  • 178
  • 215
Guillaume Vincent
  • 873
  • 1
  • 7
  • 9

7 Answers7

55

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.

Neil Smithline
  • 14,621
  • 4
  • 38
  • 55
  • 1
    so I can refresh an expired token ? why people recommend not to ? – Guillaume Vincent Apr 04 '16 at 07:12
  • ping @neil-smithline – Guillaume Vincent Jul 10 '17 at 14:45
  • 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. – Neil Smithline Jul 11 '17 at 03: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. – Guillaume Vincent Jul 11 '17 at 10:39
  • Yes. Perhaps this will help https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ – Neil Smithline Jul 11 '17 at 11:59
  • And when the refresh token expires, reauthentication is required. – Neil Smithline Jul 11 '17 at 12:00
  • what if user closes the app for 30 minutes? how to fetch new token every 15 min when app is not running? – Ali Sherafat Apr 04 '18 at 17:11
  • 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. – Neil Smithline Apr 05 '18 at 03:33
  • Got it but Does refresh token should be updated? If i set its lifetime to 1 day an user is still using the app i have to log them out? Or expand the lifetime of refresh token while using? – Ali Sherafat Apr 05 '18 at 06:17
  • @AliSherafat I don't think that there is a standard way to update the refresh token. When both access and refresh tokens expire, the user is logged out. If your refresh token has a 24 hour TTL, then your website or service requires reauthentication once a day. That's pretty common. – Neil Smithline Apr 05 '18 at 13:53
  • It's not recommended to refresh an expired JWT token. They are meant to expire for security purposes and I don't even believe it is possible to refresh and expired JWT token based on how I know that they generated. A new token should be generated per action, and each JWT claim should contain a unique identifier to track the API calls. – Justin Sep 21 '19 at 13:19
  • 2
    To add a bit more information: The ideal method according to [RFC 6819](https://tools.ietf.org/html/rfc6819#section-5.2.2.3) 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](https://supertokens.io/blog/all-you-need-to-know-about-user-session-security). – Rishabh Poddar Nov 14 '19 at 08:49
  • Thanks @RishabhPoddar - I updated the post. – Neil Smithline Nov 18 '19 at 21:41
16

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.

Sjoerd
  • 28,707
  • 12
  • 74
  • 102
  • 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 ? – Guillaume Vincent Apr 13 '16 at 07:47
  • 11
    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 '16 at 07:55
  • @Sjoerd wont that complicate things to much? the server expecting 2 jwt.. and the client keeping 2.. – Gokigooooks Sep 30 '16 at 06:22
  • I guess using two JWTs is one of the options. Another one would be to use 1 JWT, with an `exp` of 7 days, and a custom `shortExp` of 15 minutes. As long as your middleware properly checks both expire values, and re-issues the token when the `shortExp` expires, this should be fine – Laurens Rietveld Oct 10 '16 at 08:43
  • 6
    How does refreshing a token even work? Do you store the username + password of the user on the client side? – Roger Far Mar 06 '17 at 03:24
  • Do we need to extend the refresh token exp in order to maintain 7days active session when client is actively using the app? – Roel Apr 10 '18 at 15:40
  • @YesMan85 No we don't store username and password, we store refresh token on the client side and in the database against that user. When user come to server for refresh we can verify access token as well as refresh token to issue the new access token. Refresh token can be any randomly generated alphanumeric. – Nav Ali Nov 25 '18 at 23:23
  • 2
    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. – TheRealChx101 Aug 08 '19 at 00:00
  • @TheRealChx101 The whole point of JWT tokens is to make API stateless. – metalim Mar 12 '21 at 19:58
  • There's no such thing as stateless. The fact that you have to check the validity of the token everytime means there's some sort of state there. The common practice I guess is to use memcached or something of the sort. But for me, I still have to check my database for revocation. There's no way around that. – TheRealChx101 Mar 12 '21 at 21:27
6

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.

keithRozario
  • 3,571
  • 2
  • 12
  • 24
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.

Igliv
  • 361
  • 1
  • 10
  • 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. – TheRealChx101 Aug 08 '19 at 00:03
  • There are a bunch of implementations out there. Depends on which framework and language you are using.. Just a few examples: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ https://developer.okta.com/docs/guides/refresh-tokens/use-refresh-token/ – Igliv Aug 11 '19 at 10:20
5

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.

Michael Baldry
  • 151
  • 1
  • 2
  • So each response comes with an overhead of checking for a newer token. – TheRealChx101 Aug 08 '19 at 00:05
  • 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. – Michael Baldry Aug 08 '19 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. – TheRealChx101 Aug 08 '19 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. – TheRealChx101 Aug 09 '19 at 00: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. – Michael Baldry Aug 09 '19 at 08:18
4

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.

Daniel Szpisjak
  • 1,825
  • 10
  • 19
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.

Krist Jin
  • 11
  • 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](https://supertokens.io/blog/all-you-need-to-know-about-user-session-security) – Rishabh Poddar Nov 14 '19 at 09:20
  • 1
    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 '21 at 13:54