DEV Community

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

Collapse
vladimirnovick profile image
Vladimir Novick Author
  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 Author

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 on

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 Author

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.