DEV Community

Discussion on: The Ultimate Guide to handling JWTs on frontend clients (GraphQL)

Collapse
 
lvanderree profile image
Leon van der Ree • Edited

You say no to store your accesstokens on the client, in cookies or localstorage. But I wonder:

  1. Of course you have to store your JWTs somewhere (memory), to be able to provide them to your (http/rest)clients which will do the request to your APIs. And if store the in memory, aren't you still vulnerable for (targetted) XSS-attacks, or how do you protected yourself from these attacks.

  2. Even if you can protect your memory from attacks, how do you get the accesstoken in memory? You probably have some credentials in memory as well (refreshtoken) so you don't have to ask the use to relogin every 15minutes, with which you can authenticate on the authentication server to get the accesstoken. How can you prevent a (targetted) XSS-attack from not doing the same to acquire the accesstoken?

I can imagine that using sessions (or maybe tokens) in SECURE HTTP-ONLY STRICT/LAX cookies is a safer solution. If you've got (micro-)services that you want to run without all of them having to query for the session, why not put a service in front of them, that does the translation from session to JWT for calls coming from the internet. Something you probably have to do with JWTs as well, if you want to check if the valid JWT hasn't been revoked, for example when the user logged out, while the JWT hasn't been expired yet.

Collapse
 
vladimirnovick profile image
Vladimir Novick
  1. You store them in memory, but not on the global scope. So they can be accessed only from your code or if an attacker reverse engineer your code. So you should never expose memory token getter function to the outside world. That's how you can prevent attacker from getting the token.

  2. In memory, I have a getter function to get the token and every 15 minutes I do refresh_token call (silent refresh). All of this is written in the blog post in Silent refresh section

If you need to validate if your tokens were revoked or not that can be done by blacklisting them which is also described in the blog post in blacklisting tokens section. Session-based authentication is problematic in a microservices architecture. I referred to that also in blog post

Collapse
 
tkdaj profile image
tkdaj

If you only store your JWTs in memory, how do you deal with a user refreshing the browser? In my application I would like a user to be able to refresh the browser and automatically be logged back in.

Thread Thread
 
vladimirnovick profile image
Vladimir Novick

I covered that later in blog post. Short answer - refresh tokens and silent refresh. Please check the full blog post here: blog.hasura.io/best-practices-of-u...

Collapse
 
lvanderree profile image
Leon van der Ree • Edited

Hello Vladimir, thanks for your fast reply and further info.

I am looking for a way to use JWTs in a safe way, and this blog provided a good base to get more information on how to achieve this.

I read your links, but am still not convinced that JWTs (without binding) can be protected from XSS theft and misuse.

  1. I understand you should not store tokens in global scope, but somewhere in your JS-application you have a function to get the accesstoken. This function can store the token in some private property of an object, but:

    • via XSS I can create a cloned version of this version that does the same thing (see 2), but opens access to the acquired token to the hacker
    • and eventually the token should leave the private property to provide the token to (a http-client to) inject it in E.G. an authorization header. With XSS you can also inject a service that gets the accesstoken via the token-object. I am aware that this can only be done with knowledge about the working of the code, that's why I called it a targeted attack, but when the accesstoken provides access to valuable resources, this will be done.
  2. the (silent) refresh function you describe still looks vulnerable to XSS to me. You protect the refresh-token from getting stolen, but a malicious-script can call the /refresh_token API via the users browser, the cookie gets automatically applied, and now the script has an accesstoken it can publish to the hacker.

Of course CORS can be used to minimize the possibilities to inject XSS-scripts and to publish data to the outside world, but with analytic services, advertisement networks, and social-media integrations this still is very hard to prevent completely.

The best option I have seen is Token Binding but this isn't supported in browsers. You can try to implement something similar yourself with the JS-crypto functions, but then access to your API will be much harder to implement.
The safest way to provide access to your services is then by using session-cookies (although API calls can still be compromised in the same way with targeted XSS attacks; calling API's via the users browser that will automatically applies cookies, you can at least not access the API's from other systems after a token is stolen).

Thread Thread
 
vladimirnovick profile image
Vladimir Novick

I am not saying you are not 100% vulnerable, but you are way less vulnerable than in other solutions and without having a centralized token database.

As for cookie automatically applied when sent to malicious script, your cookie is http-only so it will be sent automatically only to the same domain thus reducing the risk of getting stolen. Also, it cannot be accessed through JS.