<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/do-you-store-the-jwt-in-localstorage-sessionstorage-cookies-then-this-post-is-for-you-2yol7r91m" -->

---
title: Do you store the JWT in localStorage, sessionStorage,...
description: Storing JWTs in vulnerable client-side storage (like localStorage, sessionStorage, or cookies) can expose applications to significant security risks....
canonical: https://daily.dev/posts/do-you-store-the-jwt-in-localstorage-sessionstorage-cookies-then-this-post-is-for-you-2yol7r91m
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Do you store the JWT in localStorage, sessionStorage, Cookies? then this post is for you | daily.dev
og:description: Storing JWTs in vulnerable client-side storage (like localStorage, sessionStorage, or cookies) can expose applications to significant security risks....
og:url: https://daily.dev/posts/do-you-store-the-jwt-in-localstorage-sessionstorage-cookies-then-this-post-is-for-you-2yol7r91m
og:image: https://api.daily.dev/og/posts/2yoL7r91m.png
og:image:alt: Do you store the JWT in localStorage, sessionStorage, Cookies? then this post is for you
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Do you store the JWT in localStorage, sessionStorage, Cookies? then this post is for you

**[.NET](https://daily.dev/sources/dotnetsquad)** · [@quuu](https://daily.dev/quuu) · 6 min read · 949 upvotes · 99 comments

## Summary

Storing JWTs in vulnerable client-side storage (like localStorage, sessionStorage, or cookies) can expose applications to significant security risks. Alternatives include using in-memory storage and implementing a refresh token mechanism. This allows users to maintain their sessions without re-authenticating upon page reloads while mitigating potential attacks. Setting cookies with httpOnly, Secure, and SameSite flags is crucial for security. A short-lived JWT with periodic refreshing enhances protection.

## Content

I assume you already know JWT and how to implement it so I won’t bore you with the basics. Let’s jump straight into it.

# Here’s a direct quote from Microsoft’s documentation: #

>“Storing tokens in vulnerable client-side storage can lead to significant security vulnerabilities. For example, storing access tokens directly in the browser using local storage, session storage, or web workers.”

Yet, despite this warning, many tutorials and examples online still recommend storing JWTs in browser storage I, too, used to store and retrieve JWTs directly from browser storage, because of these examples, essentially leaving the key right under the doormat.

## Why Storing JWTs in Browser Storage Is a Bad Idea ##

1.	localStorage – Vulnerable to XSS (Cross-Site Scripting) attacks.
2.	sessionStorage – Also vulnerable to XSS; the only difference is that data is wiped when the browser closes, whereas localStorage persists.
3.	Cookies – Susceptible to XSRF (Cross-Site Request Forgery) attacks unless properly secured.

## Why Do We Still Use Browser Storage? ##

The main reason is convenience. It’s easy to retrieve the token and pass it along with an HTTP request. However, persisting JWTs in browser storage exposes them to any JavaScript running in the application. For example, retrieving a token is as simple as:

localStorage.getItem('someKey');

If user input isn't properly sanitized, a hacker could inject JavaScript and do the same.
"But if we’re using frontend frameworks like Angular, aren't inputs sanitized by default?" Yes, Angular automatically sanitizes input, and other frameworks/libraries likely do the same. However, this alone is not enough.

## Here’s why: ##
1.	Third-party JavaScript libraries – If a malicious library is added  to our client site application, it can access browser storage and steal sensitive data.
2.	Browser extensions – If an extension has excessive permissions, it can read the browser’s storage and extract JWTs.
3. A game released on Steam (PirateFi) has malicious intentions of stealing information persisted in the browser storage mechanism (e.g., localStorage, sessionStorage, Cookies, etc.)

What About Cookies?

By default, cookies are not secure unless specific security flags (e.g., httpOnly, Secure, SameSite) are enabled. If JWT is manually stored in cookies from the client side, JavaScript can still read them making the cookie just another vulnerable storage mechanism. If the cookie is flagged as httpOnly, the client-side application won’t be able to access the JWT.

# The Dilemma: Security vs. User Experience #

If we don’t store JWT in any browser storage, users would need to re-authenticate every time they refresh the page. Since the client-side state resets upon refresh, this would force the user to re-enter the credentials which will lead to poor UX
So how do we balance security and good UX? 🤔We implement a silent way to issue a JWT, next is what I do. 

1.	Enforce HTTPS to encrypt the communication between the client and server.
2.	Use app.UseHSTS middleware in production to prevent downgrades to HTTP 
3.	Don’t persist the JWT use it in-memory
4.	Implement refresh token mechanism

By not persisting the JWT in the browser storage, we mitigate the attacks on the browser storage mechanism its not foolproof but its an improvement, but we still want to persist the user being login after a browser refresh so how does we do that with the refresh token.

## Heres my authentication flow for the backend. ##

When a client attempts to log in, the backend generates a JWT upon successful authentication. At the same time, it also generates a refresh token, which is not included in the response body but is instead set in the response header as an httpOnly cookie. This refresh token is also stored in the AspNetUsers table in my case.

![Screenshot 2025-02-26 032417](https://media.daily.dev/image/upload/s--HmNBbNu1--/f_auto/v1740536689/ugc/content_71fbd15b-e718-4ae6-94be-4ca00c191b7e)

### To ensure security: ###

1. The httpOnly flag prevents JavaScript access, mitigating XSS attacks.
2.	The Secure flag ensures the cookie is only sent over HTTPS.
3.	The SameSite=Strict setting mitigates CSRF attacks, meaning the client-side application and API must be on the same domain; otherwise, the refresh token will be invalid.

![Screenshot 2025-02-26 033404](https://media.daily.dev/image/upload/s--IYFSyEfA--/f_auto/v1740537273/ugc/content_5093e5fd-281c-4ca8-b534-465a7cb6a273)

4.	The Path is set to / to allow the refresh token to be sent from all endpoints.
5.	The Expires attribute is self-explanatory, defining the token's validity period.
With this setup, we maintain a single source of truth and enable JWT revocation by invalidating the refresh token.

## Client-Side Implementation ##

On the client side we implement a interceptor, whenever we encounter:
1.	A 401 Unauthorized response,
2.	A browser refresh, or
3.	The ngOnInit lifecycle hook in app.ts
we should call the refresh endpoint to validate whether the refresh token stored in the cookie matches the one in the database.

•	If valid:
1.	Generate a new JWT for the client.
2.	Generate a new refresh token and store it in both the database and the cookie.

•	If invalid:
1.	Remove the refresh token from the cookie storage.
2.	Invalidate the previous refresh token in the database.
3. Redirect the user back to login screen

By following this approach, we ensure that only the last successfully logged-in device that has a valid refresh token stored in the cookie can access the protected resources

![image](https://media.daily.dev/image/upload/s--Bs8Aj1st--/f_auto/v1740536872/ugc/content_96eb1b8b-32b7-496a-b42a-55cf70a013d9)

## Example Use Case ##
If a user forgets to log out from a work device and later logs in from their mobile device, the work device's refresh token becomes invalid. The next time the work device attempts to access a protected resource (e.g., via a browser refresh or during ngOnInit), it will be redirected to the login page because the refresh token no longer matches the database record.

I want to emphasize the importance of a short-lived JWT token something between 5-15 min because, JWT cannot be easily revoked once issued. In the scenario above, if the application remains open, the issued JWT is still valid until it either expires or a browser refresh occurs. The ngOnInit lifecycle hook will not execute since the SPA has not been closed.

you could change the value of your JWT secret but that’s a very destructive action and will be imposed on all users that currently logged in. Its better to stick with a short-lived JWT and depends on how aggressive you want you could turn the JWT to have a lifespan of only 5 min.

### lastly, I want to add an example  we all should avoid,  ### 
Ive seen example where JWT are being persisted in the sessionStorage, the token have a long expiration duration lets say 1 month, when the browser closes, the session storage is wiped. But if you click “remember me” which is an options I often see, then the JWT is being moved from sessionStorage to localStorage. This is a bad idea, if you have read the above you can imagine why this is a bad idea, alternatively we could increase the expiration of the refresh token instead.

I know this solution isn’t foolproof, but I think I’m pretty close! I believe adding a Content Security Policy (CSP) could help mitigate XSS attacks from third-party libraries, but I need to research that further.

Feel free to correct me if I’m wrong or share a better approach!

## Community discussion

Top comments from developers on daily.dev.

**@azelytof** · 46 upvotes

> I do not fully agree with you
>
> Yes you need access and refresh tokens.
> But store the last refresh token in database is rarely whr you want.
> For example, as a user, I want to stay logged on my laptop but also on my smartphone. If I switch devices I will need to authenticate every time.
>
> But you're right, we must not save access token. I also save it in local storage and that is bad practice!
>
> I'm doing n SSO app for multi domain, and I think it is bad to code it by myself.
> I think when we need to handle authentication, it is better to use known projects, as keycloak or authentika for example.

**@dodibtw** · 18 upvotes

> HTTPOnly same-site secure cookie solves all of your problems. Refresh tokens shouldn't include just the last one, as you might want to login on different devices. Just make sure your lifetimes are reasonable! (30 mins - 2 hours for JWT and 7 - 30 days for refresh token).

**@vamshinenu** · 4 upvotes

> Great information!, to add to it,
> nothing is safe, in computer world, something that sounds secure today, might be exploited, later.
>
> There are subjective good and bads ways of doing, and these generally, come from what you are doing with them, the project, the library, may also be your general coding experience.
>
> Is it safe to use cookies and JWT, universally, 'NO',
> But to some extent, where you have other mechanisms to cope with it,
>
> HTTPS, httponly, CSP's etc, even storing the IP's of users for detecting users that pose threat to the entire server.
>
> but again, do you really need that, how...

**@s\_pellegrino** · 2 upvotes

> And why not "just" a KISS : Basic auth + https... after all ?

**@javierguajardo** · 2 upvotes

> I think you never mentioned that to re-write the JWT we need the secret... I can read any JWT and that's not a problem (if you're not storing sensitive information). The "XSS" or other vulnerabilities will appear if someone can "guess" (crack) your secret ;)

## Similar posts on daily.dev

- [Don’t just attend KubeCon \+ CloudNativeCon, Merge Forward your experience\!](https://daily.dev/posts/don-t-just-attend-kubecon-cloudnativecon-merge-forward-your-experience--l0rpp73x8) · CNCF · 1 upvotes · 0 comments
- [Announcing H2 2026 KCDs](https://daily.dev/posts/announcing-h2-2026-kcds-m96goajm1) · CNCF · 1 upvotes · 0 comments
- [Two months of Open Community Groups](https://daily.dev/posts/two-months-of-open-community-groups-asf52zhbs) · CNCF · 0 upvotes · 0 comments
- [CNCF Unveils Schedule for KubeCon \+ CloudNativeCon Europe 2026](https://daily.dev/posts/cncf-unveils-schedule-for-kubecon-cloudnativecon-europe-2026-ikhcoa5cb) · CNCF · 2 upvotes · 0 comments
- [CNCF Debuts KubeCon \+ CloudNativeCon Japan 2026 Schedule](https://daily.dev/posts/cncf-debuts-kubecon-cloudnativecon-japan-2026-schedule-xp5pyudub) · CNCF · 1 upvotes · 0 comments

---

Tags: [#security](https://daily.dev/tags/security), [#webdev](https://daily.dev/tags/webdev), [#authentication](https://daily.dev/tags/authentication), [#jwt](https://daily.dev/tags/jwt)

[View this post on daily.dev](https://daily.dev/posts/do-you-store-the-jwt-in-localstorage-sessionstorage-cookies-then-this-post-is-for-you-2yol7r91m)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"DiscussionForumPosting","mainEntityOfPage":"https://daily.dev/posts/do-you-store-the-jwt-in-localstorage-sessionstorage-cookies-then-this-post-is-for-you-2yol7r91m","headline":"Do you store the JWT in localStorage, sessionStorage, Cookies? then this post is for you","text":"Storing JWTs in vulnerable client-side storage (like localStorage, sessionStorage, or cookies) can expose applications to significant security risks. Alternatives include using in-memory storage and implementing a refresh token mechanism. This allows users to maintain their sessions without re-authenticating upon page reloads while mitigating potential attacks. Setting cookies with httpOnly, Secure, and SameSite flags is crucial for security. A short-lived JWT with periodic refreshing enhances protection.","url":"https://daily.dev/posts/do-you-store-the-jwt-in-localstorage-sessionstorage-cookies-then-this-post-is-for-you-2yol7r91m","datePublished":"2025-02-26T02:36:34.852Z","dateModified":"2025-02-26T03:03:17.577Z","author":{"@type":"Person","name":"DevQu","url":"https://daily.dev/quuu","image":"https://media.daily.dev/image/upload/s--amWr0uIv--/f_auto/v1741725353/avatars/avatar_6V6DvOcuoBUswmin3eJla","description":"Former bricklayer now developer, does that makes me a blockchain developer? \n\n","interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"EndorseAction"},"userInteractionCount":910}},"image":"https://media.daily.dev/image/upload/s--frEj4WS5--/f_auto/v1740537395/posts/2yoL7r91m","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":949},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":99}],"comment":[{"@type":"Comment","text":"I do not fully agree with you\nYes you need access and refresh tokens.\nBut store the last refresh token in database is rarely whr you want.\nFor example, as a user, I want to stay logged on my laptop but also on my smartphone. If I switch devices I will need to authenticate every time.\nBut you’re right, we must not save access token. I also save it in local storage and that is bad practice!\nI’m doing n SSO app for multi domain, and I think it is bad to code it by myself.\nI think when we need to handle authentication, it is better to use known projects, as keycloak or authentika for example.","datePublished":"2025-03-02T22:43:34.053Z","url":"https://daily.dev/posts/2yoL7r91m#c-uEx5FHIqG","author":{"@type":"Person","name":"Azelytof","url":"https://daily.dev/azelytof","image":"https://lh3.googleusercontent.com/a/ACg8ocI6RrHgdhLNCYcIhA12ZPL-dV2oA0lQmAMXTmUgpDPCLvTK-YI=s96-c"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":46}},{"@type":"Comment","text":"HTTPOnly same-site secure cookie solves all of your problems. Refresh tokens shouldn’t include just the last one, as you might want to login on different devices. Just make sure your lifetimes are reasonable! (30 mins - 2 hours for JWT and 7 - 30 days for refresh token).","datePublished":"2025-03-03T07:18:12.497Z","url":"https://daily.dev/posts/2yoL7r91m#c-wuq8eK2Gz","author":{"@type":"Person","name":"Dodi","url":"https://daily.dev/dodibtw","image":"https://avatars.githubusercontent.com/u/115790541?v=4"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":18}},{"@type":"Comment","text":"Great information!, to add to it,\nnothing is safe, in computer world, something that sounds secure today, might be exploited, later.\nThere are subjective good and bads ways of doing, and these generally, come from what you are doing with them, the project, the library, may also be your general coding experience.\nIs it safe to use cookies and JWT, universally, ‘NO’,\nBut to some extent, where you have other mechanisms to cope with it,\nHTTPS, httponly, CSP’s etc, even storing the IP’s of users for detecting users that pose threat to the entire server.\nbut again, do you really need that, how important is your user data (not just their name, email) but in general the data they work with.","datePublished":"2025-03-04T18:30:17.366Z","url":"https://daily.dev/posts/2yoL7r91m#c-rQ3vrBVa3","author":{"@type":"Person","name":"vamshi nenu","url":"https://daily.dev/vamshinenu","image":"https://media.daily.dev/image/upload/s--2n9M9oyT--/f_auto/v1722792477/avatars/avatar_4EkOlKq6lXhuJcnOVH9ee"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4}},{"@type":"Comment","text":"And why not “just” a KISS : Basic auth + https… after all ?","datePublished":"2025-03-03T11:44:37.290Z","url":"https://daily.dev/posts/2yoL7r91m#c-APiowF3PF","author":{"@type":"Person","name":"Stephane Pellegrino","url":"https://daily.dev/s_pellegrino","image":"https://lh3.googleusercontent.com/a-/AOh14GhHJZpb7nUO6ZPald1_9_4fVgcBQwejZIvVYRrvZQ=s100"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2}},{"@type":"Comment","text":"I think you never mentioned that to re-write the JWT we need the secret… I can read any JWT and that’s not a problem (if you’re not storing sensitive information). The “XSS” or other vulnerabilities will appear if someone can “guess” (crack) your secret ;)","datePublished":"2025-03-06T07:15:26.738Z","url":"https://daily.dev/posts/2yoL7r91m#c-k3zMrJBor","author":{"@type":"Person","name":"Javier Guajardo","url":"https://daily.dev/javierguajardo","image":"https://media.daily.dev/image/upload/s--QlByi6Yg--/f_auto/v1750366205/avatars/avatar_Kwp6RHfZKi4h95oTpl029?_a=BAMClqZW0"},"interactionStatistic":{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2}}],"isPartOf":{"@type":"WebPage","url":"https://daily.dev/squads/dotnetsquad","name":".NET"}}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":".NET","item":"https://daily.dev/squads/dotnetsquad"},{"@type":"ListItem","position":3,"name":"Do you store the JWT in localStorage, sessionStorage, Cookies? then this post is for you"}]}
```

