İçeriğe Atla
Mustafa Erbay
Tutorials · 11 min read · görüntülenme Türkçe oku

JWT Storage: LocalStorage or HttpOnly Cookie?

I explore the intricacies of securely storing JWT tokens in web applications, comparing LocalStorage and HttpOnly Cookies.

100%

The use of JSON Web Tokens (JWT) is quite common in web applications for user authentication and authorization processes. However, securely storing these tokens on the client-side (browser) is a critical issue that should not be overlooked. There are generally two main options we encounter: the browser’s localStorage or HttpOnly cookies. Let’s take a deep dive into the advantages, disadvantages, and scenarios where we should prefer one over the other.

In this comparison, I will cover many aspects of both storage mechanisms, from security to performance, ease of use to scalability. My aim is to help you make the right decision for your own projects. Remember, choosing a technology always involves a trade-off, and the best solution is shaped by the specific needs of your project.

The Nuances and Risks of LocalStorage

localStorage is a key-value based storage mechanism offered by the browser. Data persists even if the browser is closed and is easily accessible via JavaScript. This simplicity might seem appealing for storing tokens like JWTs. However, this ease comes with significant security vulnerabilities.

The biggest risk is that localStorage is readable by JavaScript. This means any JavaScript code running on your web page (your own code, third-party libraries, or worst of all, malicious code injected as a result of a Cross-Site Scripting (XSS) attack) can access your tokens. When an XSS vulnerability is detected, attackers can steal a user’s session and act on their behalf. For example, when you unknowingly execute malicious script while commenting on a blog site or sending a message on a forum, your JWT in localStorage can be directly compromised.

Furthermore, localStorage’s storage capacity is typically around 5MB, which might not be enough for large tokens or additional data. From a performance perspective, reading and sending data from localStorage on every request can create an additional overhead on the browser’s JavaScript engine. Therefore, when using localStorage for JWT storage, potential security risks and performance impacts must be carefully evaluated.

A Real-Life Case: XSS and Token Theft Experience

A few years ago, on a client project, we were working on a web application where users created interactive reports. The application’s frontend was written with Vue.js and used JWT authentication. Tokens were stored in localStorage. Towards the end of the development process, a security tester found an XSS vulnerability in an input field within a dynamically generated chart component. The attacker, by injecting specially crafted script into this field, could control the JavaScript running on the page.

The tester, using this vulnerability, executed the command localStorage.getItem('authToken') and successfully hijacked the user’s session with the obtained token. This situation required immediate intervention. We quickly released a hotfix, disabled the script execution feature in the relevant input field, and asked all users to refresh their tokens. After this incident, we decided to migrate the project’s JWT storage strategy to HttpOnly cookies. This experience painfully demonstrated how vulnerable localStorage is to XSS attacks.

Security Advantages of HttpOnly Cookies

Cookies with the HttpOnly flag are automatically sent to the server by the browser and cannot be accessed by JavaScript. This, unlike localStorage, significantly prevents XSS attacks from stealing tokens. This is because malicious scripts cannot access HttpOnly cookies via document.cookie. This feature makes HttpOnly cookies a more secure option for storing sensitive information like JWTs.

An HttpOnly cookie is sent to the browser with a Set-Cookie HTTP header. For example, when your server-side application (e.g., using Express with Node.js) generates a JWT, it can send this token to the browser with a header like this:

Set-Cookie: authToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; HttpOnly; Secure; SameSite=Strict; Path=/

The HttpOnly flag here prevents JavaScript from accessing this cookie. The Secure flag ensures the cookie is only sent over HTTPS, providing an additional layer of protection against man-in-the-middle (MITM) attacks. SameSite=Strict ensures the cookie is only sent with same-site requests, reducing the impact of CSRF (Cross-Site Request Forgery) attacks.

However, HttpOnly cookies also have their own challenges. Since browsers send these cookies automatically, when you want to read the token on the client-side and perform operations on it (e.g., taking the token from the cookie and adding it back to the header when preparing an API request, instead of adding it to the header), you won’t have direct access. This situation might require you to make certain architectural decisions, especially when developing SPAs (Single Page Applications).

CSRF Protection with HttpOnly Cookies

Another important security feature of HttpOnly cookies is the protection they offer against Cross-Site Request Forgery (CSRF) attacks when used with the SameSite attribute. CSRF attacks aim not to steal the user’s session, but to use the user’s browser to perform actions the user has not approved or is unaware of.

For example, while a user is logged into a banking site, a malicious website might secretly send a payment order to the banking site without the user’s knowledge. If the session information is stored in HttpOnly cookies and these cookies are set to SameSite=Strict, the browser will not send the cookie for this request coming from a different site. This leads to the CSRF attack failing.

Set-Cookie: sessionId=abc123xyz; HttpOnly; Secure; SameSite=Strict

In the example above, the SameSite=Strict setting enforces that the cookie is only sent for requests to the same site (i.e., requests originating from bank.com). If a user is on malicious.com and a POST request is made to bank.com, the browser will not include the sessionId cookie in this request. This is a strong defense mechanism against CSRF attacks.

However, the SameSite=Strict setting can negatively affect user experience in some situations. For example, if a user clicks a link from one site (e.g., siteA.com) to another site (siteB.com) and needs to log in to siteB.com, the Strict mode might block this request because the request originates from a different “site”. In such scenarios, SameSite=Lax might be a more suitable option.

Architectural Approaches to Managing JWTs

When using HttpOnly cookies, how we send the JWT to the server is an important architectural consideration. Traditionally, authentication tokens are sent with the Authorization: Bearer <token> header. However, since HttpOnly cookies are inaccessible to JavaScript, we cannot apply this approach directly.

In this case, two common strategies can be followed:

  1. Server-Side Rendering (SSR) or Hybrid Approaches: If your application is rendered on the server-side (e.g., with frameworks like Astro, Next.js, Nuxt.js), the server can read the token from HttpOnly cookies upon receiving a request and use it directly in API requests. In this scenario, client-side JavaScript does not need to access the token.

  2. API Gateway or Backend for Frontend (BFF): By using a separate BFF layer, you can receive client requests, read the token from HttpOnly cookies, make requests to the actual service APIs with this token, and return the results to the client. This eliminates the complexity of token management on the client side.

If your application runs entirely on the client-side and you are using HttpOnly cookies, you might need to use an intermediary layer on the server side (e.g., an Nginx proxy_set_header directive or a Node.js server) to add the token to a header. This intermediary layer will take the token from the incoming request’s HttpOnly cookie and add it to the Authorization header of the request sent to the target API. This approach simplifies client-side code and reduces security risks.

Comparison of Storage Options

The following table summarizes the key features of localStorage and HttpOnly cookies:

Feature LocalStorage HttpOnly Cookie
Access Method JavaScript Browser (with automatic requests)
XSS Protection None (Easily stolen) Yes (JavaScript access is blocked)
CSRF Protection None (Requires manual implementation) Yes (With SameSite attribute)
Storage Capacity Typically 5MB Varies by browser and site (generally more)
Session Duration Persistent until cleared by the browser Determined by Expires or Max-Age
Automatic Sending No (Must be manually added to request header) Yes (To all requests to the relevant domain)
Ease of Use High (Simple access via JavaScript) Medium (Intermediary layer or SSR may be required)
Security Low High

Looking at this table, we can clearly say that HttpOnly cookies are a significantly more secure option than localStorage for storing sensitive information like JWTs. The ease of localStorage requires serious compromises in terms of security.

Performance and Scope Analysis

From a performance perspective, reading and writing data from localStorage consumes CPU cycles on the JavaScript engine. Retrieving the token and adding it to the HTTP header on every request creates a small performance cost, especially in applications that make frequent API calls. On the other hand, HttpOnly cookies are managed automatically by the browser and sent as part of the HTTP request. This reduces the workload on client-side JavaScript.

However, HttpOnly cookies can also have some potential performance impacts. Especially if there are large tokens or a large number of cookies, the amount of data sent with each request increases. This can affect network bandwidth and server-side processing time. Nevertheless, these impacts are generally negligible when compared to the potential cost of XSS attacks.

In terms of scope, localStorage operates on a browser basis, and cookies are similarly tied to the browser and domain. However, with additional attributes like Secure and SameSite for HttpOnly cookies, it’s possible to implement more granular control and advanced security policies. This makes HttpOnly cookies a more comprehensive security solution.

Ongoing Issues and Solution Recommendations

While HttpOnly cookies are a more secure option than localStorage, they are not perfect. In particular, managing HttpOnly cookies can introduce some additional complexities for developers. For example, the inability of client-side JavaScript to access the token can create difficulties in some modern frontend architectures.

As a solution, the BFF (Backend for Frontend) pattern is quite effective. The BFF layer receives client requests, retrieves the token from HttpOnly cookies, makes the necessary service calls, and returns the results to the client. This way, the client side only communicates with the BFF, and token management is handled entirely on the server side. This approach is a great way to simplify the client side, especially in complex microservice architectures.

Another potential issue is the synchronization of cookies across browsers or managing sessions on different devices. If a user accesses the application from different devices and you want their sessions to be synchronized, HttpOnly cookies alone might not be sufficient. In such cases, using HttpOnly cookies in conjunction with a centralized session management mechanism on the server side might be more sensible.

Furthermore, browser cookie policies can change over time, leading to unexpected behavior. Therefore, it’s important to follow current browser documentation and ensure that attributes like HttpOnly, Secure, and SameSite are implemented correctly.

Conclusion: A Security-First Approach

So, localStorage or HttpOnly cookie? Based on my experience and the analysis presented here, HttpOnly cookies should definitely be preferred for storing sensitive authentication tokens like JWTs. The easy accessibility of localStorage via JavaScript makes it excessively vulnerable to XSS attacks. An XSS vulnerability can directly lead to session hijacking by stealing the token from localStorage.

HttpOnly cookies eliminate this risk by being automatically managed by the browser and hidden from JavaScript. When combined with the SameSite attribute, they also provide strong protection against CSRF attacks. The minor additional complexity they introduce during development is quite insignificant compared to the security advantages they offer.

If you are developing a modern SPA and find it challenging to work with HttpOnly cookies, you can overcome these difficulties by adopting approaches like a BFF layer or server-side rendering (SSR). Remember, web security is a continuous battle, and every correct architectural decision we make can make a big difference in protecting our users’ data.

The next step is to integrate HttpOnly cookies into your application to securely store your JWTs. This will ensure that both you and your users are safer.

Paylaş:

Bu yazı faydalı oldu mu?

Yükleniyor...

Bu yazı nasıldı?

Frequently Asked Questions

Common questions readers have about this article.

What are the main differences between LocalStorage and HttpOnly Cookies?
In my experience, the main differences between LocalStorage and HttpOnly Cookies lie in security and access control. LocalStorage is a key-value based storage mechanism in the browser and is readable by JavaScript. This means it can be accessed by any JavaScript code running on your web page. On the other hand, HttpOnly Cookies are only accessible by the server and cannot be read by JavaScript. This can be a more secure option, especially for storing sensitive data like JWTs.
What are the advantages and disadvantages of storing JWT tokens in LocalStorage?
In my opinion, the advantages of storing JWT tokens in LocalStorage include ease of use and flexibility. Tokens can be easily stored and accessed by JavaScript. However, a major disadvantage is that tokens in LocalStorage are vulnerable to XSS attacks. An attacker can steal your tokens through JavaScript code running on your web page. Therefore, before storing JWT tokens in LocalStorage, it's important to develop defense strategies against XSS attacks.
What are the advantages and disadvantages of using HttpOnly Cookies?
In my experience, the advantages of using HttpOnly Cookies include security and protection. HttpOnly Cookies are only accessible by the server and cannot be read by JavaScript, making them more secure against XSS attacks. However, as a disadvantage, the use of HttpOnly Cookies is more complex and must be configured on the server side. Additionally, some browsers and devices may not support HttpOnly Cookies. Therefore, before using HttpOnly Cookies, it's important to consider browser and device compatibility.
What is the best approach for storing JWT tokens?
In my opinion, the best approach for storing JWT tokens is to strike a balance between security and convenience. Both LocalStorage and HttpOnly Cookies can be used, but the advantages and disadvantages of each should be considered. My recommendation is to use HttpOnly Cookies, especially for applications requiring high security, and to develop defense strategies against XSS attacks. However, for simpler applications, LocalStorage can also be used, provided that the necessary security measures are taken.
ME

Mustafa Erbay

Sistem Mimarisi · Network Uzmanı · Altyapı, Güvenlik ve Yazılım

2006'dan bu yana sistem mimarisi, network, sunucu altyapıları, büyük yapıların kurulumu, yazılım ve sistem güvenliği ekseninde çalışıyorum. Bu blogda sahada karşılığı olan teknik deneyimlerimi paylaşıyorum.

Kişisel Notlar

Bu notlar sadece sizde saklanır. Tarayıcınızda yerel olarak tutulur.

Hazır 0 karakter

Comments

Server-side AI Moderation

Comments are AI-moderated server-side and stored permanently.

?
0/2000

Server-side AI moderation

✉️ Free · No spam · Unsubscribe anytime

Get notified about new posts

New content and technical notes — straight to your inbox.

  • 📌
    Best of the week Single most-worth-reading post
  • 🔧
    Toolbox notes Real tools I used this week
  • 🧠
    Behind-the-scenes Notes that don't make it to blog

We don't spam. Unsubscribe anytime. · Tracked only by Umami (self-hosted, no Google).

Your Reading Stats

0

Posts Read

0m

Reading Time

0

Day Streak

-

Favorite Category

Related Posts