19

In my current architecture, my backend issues a JWT back to the (mobile) client. The primary reason to opt for a JWT is stateless authentication, i.e. the server doesn't need to store data in the session/database, which means less overhead and scalability issues.
A common strategy is to log in the user and return back the short-lived JWT (approximately 15 minutes - as I read), together with a refresh token that the user stores in the client. The refresh token never expires, and can only be revoked. The purpose would be to avoid sending a long-lived JWT over the wire too many times, and only refresh the JWT when expired; when an attacker would get hold of the short-lived token, the attack time window is brief.

The problem is that this story seems to be full of holes when I think about it. Please help me clarify.

  1. A 15 minute expiration time would mean that some users might as well send a refresh token over the wire 10 times/day. That might just be as high a frequency as some user would make requests with a regular, short-lived access token. Therefore the argument of the refresh token seems questionable.
  2. If you question SSL, then I don't know why so many companies use basic authentication. To use JWT with refresh token, you probably should use HTTPS anyway.
  3. What is the benefit of JWT if you then need to store a refresh token in the session/database in order to issue a new jwt to the client. In this case, the refresh token would act as a sort of password (although I realise it's not exactly the same) that gets stored in the backend. This makes the authentication flow essentially stateful and seems to take away the benefit of using JWT altogether. Also, with a brief expiration period of 15 minutes, it means that you have a lot of overhead, needing to get a refreshed access token almost every time you check your phone if there is a 30 minutes interval. Not only is there the overhead to check the stored refresh token, additionally you need to check whether the refresh token is blacklisted, which means another performance overhead. (Edit: the last check can be removed by just removing the refresh token from the db when revoked).
  4. A refresh token requires multiple server roundtrips:
    • 401 is returned when the access token has expired (resource server).
    • A new access token needs to be requested at the auth server
    • The request to the resource server needs to be re-initiated.

Can someone explain to me what I'm missing here?

arif
  • 1,088
  • 13
  • 24
Trace
  • 327
  • 3
  • 14

2 Answers2

14

One of the main criticisms of stateless session tokens is the lack of a secure logout. Having a separate access/refresh token allows a compromise. You can greatly reduce the amount of database access, while having a secure logout function with a 15-minute delay.

The design doesn't do anything to protect against session hijacking, i.e. malicious capture of the token. Just use SSL, it is ubiquitous these days.

You can reduce the amount of round trips with some care. Many client HTTP libraries allow you to perform proactive authentication, which avoids the extra round-trip to get a 401.

I agree that it's not a particularly sensible design. Most web site are database heavy anyway, so checking a token on each request isn't much more overhead. And while the basic concept of access/refresh tokens is secure, I worry that the extra complexity invites implementation flaws.

paj28
  • 32,736
  • 8
  • 92
  • 130
  • Thanks for your answer. About the secure logout; it seems to bump into the same question. If you use SSL, the transport security is taking out of the question, and I don't see a scenario where the attacker can get the access token, but not the refresh token. Given a 15 min expiration for the access token, the refresh token is sent over the wire continuously, almost as many times as an actual access token in some scenarios. – Trace Jun 21 '17 at 06:39
  • @KimGysen - One scenario is use of a shared PC. Although this is pretty rare now everyone uses their phone. And clearing browsing history is probably the best defence. – paj28 Jun 22 '17 at 05:23
  • RefreshToken and accessToken would be stored in the same place, given phone / PC so how does it differ? – Trace Jun 22 '17 at 14:13
  • @KimGysen - Providing a strong logout function is desirable. If they logout from a shared PC, people want to be confident they have really logged out, and the next person can't resume their session. Also useful for remote logout which Gmail/Facebook now provide, and functions like change password. If you don't have separate refresh/access then the only way to have strong logout is to check the token against the database on every request. Perhaps I should put this parargraph in the answer. – paj28 Jun 22 '17 at 16:59
  • I'm not trying to be difficult on purpose here. But in your initial answer you mention that checking a token on each request isn't much overhead... And it's exactly what happens when you have a shortlived access token of 15 mins. Let's take FB; if I would check my feed every half hour without further action, then the refresh token is sent / verified basically every time. If I would use session to store the refresh token (which is faster) then it basically takes away the benefit of jwt regarding scaling. I'm thinking to prolong the access token expiration to a day. – Trace Jun 22 '17 at 18:54
  • 2
    @KimGysen - no worries. When you check your FB feed, it probably does several dozen requests. That's one database session query vs several dozen. I think for most apps it's still not much overhead, but I was trying to explain why apps don't want to go down the route of purely stateless session tokens. At this point, I think you understand the tradeoffs involved, so I'm sure you'll make an informed decision. – paj28 Jun 22 '17 at 19:24
1

Unless there are other answers to this question, my own current solution is that it is a question of assessing the tradeoffs of security risk against performance.

My main consideration is to increase the time window of the "short lived" jwt access token of 15 minutes to a day.
This given that HTTPS is required, and that requests are only made internally, i.e. the tokens don't travel cross-domain.

This means that in terms of performance, the token refresh only happens once a day. Theoretically, SSL should provide sufficient security in my case; a single day of attack window is merely a security measure on top of something that shouldn't happen in the first place.

Although refresh tokens essentially make the authentication process stateful, this may be acceptable since most requests (in this case over a day) to the resource server still happen using the jwt.

Trace
  • 327
  • 3
  • 14