6

A lot of questions have already been asked on the topic of storing JWT tokens securely when dealing with a browser-based application. The consensus seems to be that http-only, secure cookies should be used. However, many variations seem to exist on storing JWT tokens when both short-lived access tokens and longer-lived refresh tokens are involved.

I have identified the following variations:

1. Store both JWT access token and refresh token in http-only, secure cookies

Pros:

  • Access token and refresh token cannot be accessed from Javascript

Cons:

  • Introduces CSRF vulnerabilities so CSRF token must be added as well

The top answer here advises to add CSRF tokens: https://stackoverflow.com/a/37396572/6735966

2. Store a JWT access token in memory and refresh token in http-only, secure cookie

Pros:

  • Refresh token cannot be accessed from Javascript
  • Access token sent through Javascript so access token is not vulnerable to CSRF
  • Refresh cookie can only be used to obtain new access token. With the correct CORS setup, reading the access token from the response is not possible through a cross-site request by a malicious party. Therefore, this approach seems safe from CSRF.

Cons:

  • Access token can be accessed through Javascript (but access token expires quickly)

Recommended here but received a lot less votes than the top post: https://stackoverflow.com/a/63593954/6735966

3. Store a refresh token in memory and JWT access token in http-only, secure cookie

Pros:

  • Access token cannot be accessed from Javascript
  • Refresh token sent through Javascript so refresh token is not vulnerable to CSRF

Cons:

  • Longer-lived refresh token can be accessed from Javascript
  • Access token is vulnerable to CSRF

A similar approach is described in the top answer here: https://stackoverflow.com/a/54378384/6735966

Considering the pros and cons storing a JWT access token in memory and refresh token in http-only, secure cookie definitely seems like a good idea to me. However, even though there are many questions on this topic, none of the top voted answers even consider this approach. Therefore my question is: Why not store JWT access token in memory and refresh token in cookie and instead use one of the other approaches?

1 Answers1

0

Storing the cookie in memory would work, but one issue is if you have multiple instances of the same client.

An alternative is to do it like they do in ASP.NET core, where by default the cookies are stored encrypted in the session cookie. However, this cookie can't be used to access any API's, as it is inaccessible from JavaScript. Also, to avoid the CSRF issues, you typically add the common antiforgery token/cookie to prevent CSRF attacks.

So, the most way is to store the tokens in ASP.NET Core is in the session cookie. But at the sametime, this make the cookie to grow quite a bit, so when you feel the cookie size grows to big, then you start looking at storing them in memory or in database/Redis storage.

In .NET for example, the support for this is already built in by using a SessionStore. The picture below tries to show how this works where the SessionKey is stored in the cookie and then tokens are stored in memory/backend.

enter image description here

Yes, this is how it works in ASP.NET Core and I am sure you can find the similar approaches in other platforms as well.

An alternative is to look at using the BFF pattern that seems to get more and more popular.

Tore Nestenius
  • 16,431
  • 5
  • 30
  • 40
  • Would you mind explaining why having multiple instances of the same clients is an issue? – Just van der Veeken Dec 10 '21 at 12:25
  • if you have multiple instances, then how do you share the tokens across the different services? (unless you use sticky sessions in the load balancer). With service you prefer to have them stateless. Also there is an issue to make sure encrypted cookies works across different service instances, for some frameworks that needs extra care and configuation. – Tore Nestenius Dec 10 '21 at 12:59
  • I'm sorry but I still don't understand. I assume that with multiple client instances you mean for example two single page applications (SPA's) that authenticate to the same REST api. The JWT access token is stored in browser memory and refresh token in a cookie. Since the REST api is stateless, why would the services need to share the token? – Just van der Veeken Dec 10 '21 at 14:58
  • It was a bit unclear in your question if you where using a classic backend site or if it was a SPA, I assumed the former. The question for SPA applications is security and how to manage the tokens. One way is to use the BFF pattern to avoid dealing with the complexity of storing and securing tokens in the browser. – Tore Nestenius Dec 10 '21 at 15:12
  • I think the more you can handle in the backend, the better it is for the security. – Tore Nestenius Dec 10 '21 at 15:13
  • Apologies, my question assumes that we want to store both a JWT access token and refresh token in the browser and what would then be the best approach. – Just van der Veeken Dec 10 '21 at 15:16
  • Well, if you let JavaScript access your tokens, then you will have quite some security issues regardless..Tokens stored as a HttpOnly cookie will be pretty useless to have, because you can't use them to call API's using the authorize header. Then its better to have a BFF pattern and just a plain session cookie – Tore Nestenius Dec 10 '21 at 15:22