Are you storing the JWT properly?

Tram Ho

There is a simple question, but many of you are still confused as “How to save tokens in the browser in the most standard, safe and effective way”, then in this article, that question will be answered

Stolen JWT

What are tokens?

JWT (JSON Web Token) is an encrypted piece of code containing authentication and authorization information in web and mobile applications. It consists of three main parts: Header, Payload and Signature. JWT is portable, does not need to save session state on the server and helps improve performance. However, using JWT also requires security considerations. When the JWT is signed with a secret key, it is necessary to ensure that the secret key is carefully protected to prevent the token from being tampered with or edited for malicious purposes.

The problem posed

From personal experience, I see a lot of applications using local storage or session storage as well as using unsecured cookies . These ways reveal a lot of weaknesses such as being very easily attacked by XSS, CSRF leading to private information being exposed.

For that reason, in this article we will take a look at alternatives like Closure, Secure Cookie and Service Worker that use client-side Jquery and backend Nodejs to implement API creation and authentication.

My source code is here https://github.com/quocthinh861/jwt-token-storage

Discover

The application is divided into 2 parts: frontend and backend

Each directory will have its own package.json file and is run independently with the command npm start

The frontend is run on port 4000, the backend is on port 3000. When successfully launched, http://localhost:4000 will appear as shown below.

When the user is not logged in, the login and logout buttons will be disabled.

Closure

This technique is intended to keep the token’s “in-memory” value inside an anonymous function (or closure). As such, the variable has local scope and cannot be read or accessed by any other script or software.

In the code in the master branch, the token is wrapped in the function “$(document).ready”

When the user presses login, the API “/login” will be called and the JWT Token will be sent to the client

JWT token expires after 5 minutes, so after login, refreshToken is called every 4 minutes to maintain token validity.

This technique is safe and very simple to implement, however, every time the user refreshes the page, the token is lost and you need to login again.

Secure Cookies

Another technique, in common use, involves sending the token through a cookie with the following options:

  • sameSite: true → to apply strict same site rules
  • httpOnly: true → do not allow JavaScript to read cookies
  • secure: true → to send the cookie back to the server in the future if the browser only has HTTPS connection
  • maxAge: number → should not exceed 30 minutes

The only downside to this technique is that cookies will not be available across domains.

Service Worker

And finally a most secure but somewhat complicated technique. The Service Worker runs on a separate thread, allowing the token to remain available even after a page reload.

Service Worker acts as a background script that runs independently of the browser’s main thread. It can intercept network requests, handle caching, and perform many other tasks, including managing authentication tokens.

By storing the token in the scope of the Service Worker, the token remains available even if the site is reloaded or closed and reopened. This ensures users remain authenticated and can continue to access protected resources smoothly.

Deploying this technique requires setting up and configuring the Service Worker in your web application. The Service Worker will intercept requests and check for the existence of a valid token, then provide that token to the application even if the web page is reloaded.

Page reload

On page reload, we fire up the service worker and check for the existence of a token. If so, we validate the token by sending a request to the server.

When the service worker is ready, we call refresh token to check if the token is still valid.

Set the tokens

Tokens should only be set through service workers in the login response to avoid being intercepted by XSS attacks or malicious code.

When logging out or when an error occurs, the user informs the service worker to remove the token.

Make sure that the results returned to the user will not include tokens.

fetch method interception

Looking at the service worker, we listen to the fetch method to inject the token when it’s available:

Note: XMLHttpRequest ($.ajax) cannot be interfered with by service workers, so we use fetch instead.

However, when using fetch, we need to take care to protect it from XSS payload:

Evergreen browsers

While this technique is safe and effective in handling page reloads, it should be noted that not all browsers support service workers. Service workers are a feature of modern browsers, known as evergreen browsers, that comply with the latest web standards.

End

In this article, we tried to explore three techniques to properly store tokens across browsers.

The implementation I provided doesn’t use HTTPS. The purpose is just to interact with a cross-domain backend and technical demonstration.

The full source code is available at: https://github.com/quocthinh861/jwt-token-storage

Each technique is implemented in a particular branch, respectively: closure, cookie, and service-worker.

Share the news now

Source : Viblo