How to Securely Store JWT Tokens in the Frontend

Web applications have become a critical part of daily life, providing everything from social media interactions to online banking. One of the most common ways to authenticate users is through JSON Web Tokens (JWTs). However, storing JWT tokens securely is just as important as implementing them. In this article, we will explore the best practices for securely storing JWT tokens in the frontend and why certain methods are better than others.

What Is a JWT Token?

A JSON Web Token (JWT) is a compact, URL-safe token format used for transmitting information between parties as a JSON object. It is often used for authentication and authorization in modern web applications.

A typical JWT consists of three parts:

  1. Header – Contains metadata about the token (like the signing algorithm).

  2. Payload – Contains the claims (the data you want to send, like user information).

  3. Signature – Ensures the token’s authenticity and integrity.

Why Is Secure Storage of JWT Tokens Important?

When implementing JWT for authentication, the token is typically stored in the client-side to be sent with requests to authenticate API calls. However, improper storage of these tokens can make your application vulnerable to attacks such as Cross-Site Scripting (XSS) or Cross-Site Request Forgery (CSRF).

To keep your application secure, you must choose the best way to store the token and avoid common pitfalls.

Best Practices for Storing JWT Tokens in the Frontend

Here are the recommended methods for securely storing JWT tokens in the frontend:

The most secure and recommended way to store JWT tokens is in HttpOnly cookies. These cookies are automatically sent with each HTTP request and are not accessible by JavaScript, making them safe from XSS attacks.

Why HttpOnly Cookies Are Secure:

  • HttpOnly flag: Ensures that the cookie cannot be accessed through JavaScript, protecting it from XSS attacks.

  • Secure flag: Ensures that the cookie is only sent over HTTPS connections, preventing it from being exposed during unencrypted communication.

  • SameSite attribute: Helps protect against CSRF attacks by controlling whether cookies are sent with cross-site requests.

Example Implementation:

document.cookie = "token=<your-token>; HttpOnly; Secure; SameSite=Strict; path=/";
  • HttpOnly: Ensures the token is inaccessible via JavaScript.

  • Secure: Ensures the cookie is only sent over HTTPS.

  • SameSite=Strict: Prevents the cookie from being sent with cross-origin requests (protects from CSRF).

  • path=/: Makes the cookie available for all paths in your domain.

In Next Blog Will Explore how to implement this flow in Backend + Frontend

2. Avoid LocalStorage and SessionStorage (Not Secure)

Many developers mistakenly use localStorage or sessionStorage to store JWT tokens due to their ease of use. However, these storage mechanisms are vulnerable to XSS attacks because they can be accessed directly by JavaScript running on the page.

If an attacker injects malicious JavaScript (e.g., through an XSS attack), they can easily retrieve the token and impersonate the user.

Why You Should Avoid These:

  • Accessible by JavaScript: Tokens stored in localStorage or sessionStorage can be read by any script running on the page.

  • XSS Vulnerability: If the site is compromised by an XSS attack, tokens stored here are immediately at risk.

Thus, never store sensitive data like JWT tokens in localStorage or sessionStorage.

3. Implement Refresh Tokens for Long Sessions

In cases where your application requires longer user sessions, refresh tokens are a better option. The idea is to store the refresh token securely (using an HttpOnly cookie) and use it to obtain new access tokens when they expire.

This approach allows you to use short-lived access tokens that are less prone to being compromised, while the refresh token has a longer lifespan and can be used to obtain a new access token when needed.

Example Flow:

  • The user logs in and receives both an access token (short-lived) and a refresh token (long-lived).

  • When the access token expires, the frontend uses the refresh token (sent in an HttpOnly cookie) to obtain a new access token from the server.

  • The refresh token is also securely stored and is never directly accessible by JavaScript.

This flow ensures that even if an access token is compromised, the refresh token (stored securely) can still help limit the damage by renewing the access token before it expires.

4. Avoid Storing Sensitive Information in JWT

Another key point when working with JWTs is that sensitive information should never be stored in the JWT payload. Although JWTs can be signed to ensure their integrity, they can be decoded easily by anyone who has access to the token.

What Not to Store:

  • Passwords: Never store passwords or any other highly sensitive data in the JWT payload.

  • Credit card information: Sensitive financial data should never be in a JWT token.

Instead, the JWT should carry minimal user information necessary for the authentication process (e.g., user ID, roles, permissions), and any sensitive data should remain on the server.

5. Additional Client-Side Security Measures

While storing JWT tokens securely is a top priority, there are other ways to enhance security:

  • Content Security Policy (CSP): Implement a robust CSP to restrict which resources can be loaded on your page, reducing the risk of XSS attacks.

  • Subresource Integrity (SRI): Use SRI to verify the integrity of third-party libraries, ensuring they haven't been tampered with.

Conclusion

Securing JWT tokens in the frontend is essential to maintaining the integrity of your web application's authentication system. The best practice is to store JWT tokens in HttpOnly cookies, as they are not accessible via JavaScript and are protected from common attacks like XSS and CSRF. Avoid storing JWT tokens in localStorage or sessionStorage, as these are vulnerable to XSS attacks.

By following these best practices, you can help ensure that your JWT-based authentication system remains secure and your users' data stays safe.