Hacker News new | ask | show | jobs
by Maxion 980 days ago
It's interesting how much of an upward hill battle it has been for me to argue that JWT tokens need to be stored in cookies rather than LocalStorage. In my latest project, the lead backend dev is convinced it is insecure to store the accessToken in a HTTPOnly cookie, and that it HAS to be stored in LocalStorage.
4 comments

I'm curious what were their reasons - it's hard to imagine how localStorage would be "more secure" than http only cookies.

It's not a zero-sum situation. There are risks and vulnerabilities in every approach, that's why we as web devs take advantage of multiple safeguards to ensure safety when sensitive information is to be transmitted over the wire.

My best guess is that they are thinking of CSRF. With cookies, requests automatically carry the token, whereas with local storage you need to explicitly add the token. However, CORS does a lot to improve this situation. I note that CORS allows posting form data without pre-flight, but it is not immediately clear to me if posting a form cross domain will send cookies.
> but it is not immediately clear to me if posting a form cross domain will send cookies.

As sibling comment says, this is what SameSite is for.

If it's a POST form, SameSite=Lax or SameSite=Strict won't send the cookie.

If it's a GET form, SameSite=Strict won't send the cookie. SameSite=Lax might, I'm not entirely sure.

This is what the SameSite setting on the cookie controls
It depends on the use case. For example, if your app uses WebSockets for all its data, authentication and access control and only uses HTTP for static files, you may not want the JWT to be sent to the server as a cookie with each HTTP request as it would be wasteful so localStorage may be more appropriate.

However, with cookies, you have to be careful with the SameSite flag and also be mindful that some older browsers may not support it and so it can be tricky to fully restrict where the cookie will be sent in all scenarios.

But aren't HTTPonly coookies stored in a SQLite db, and have no password attached in Firefox or Chrome?
Both cookies and localStorage are usually stored in an SQLite db…

localStorage is totally accessible to any JavaScript running on the page, so your session can be completely hijacked and used later.

> so all it takes is a little injected script

If you can inject javascript, it's game over anyway.

> HTTPOnly cookies are safe from XSS attacks.

No, you can still do pretty much anything that cookie enables you to do. You just can't get the actual cookie string.

> If you can inject javascript, it's game over anyway.

Yeah, but as you pointed out the one thing you can't do is get the cookie. Having the auth token yourself as the attacker is a way different story then just having XSS vulnerabilities. You can still "do" a lot, but you still have to get another user with the token you want to interact with the page with your XSS to "do" what you want.

> You can still "do" a lot, but you still have to get another user with the token you want to interact with the page with your XSS to "do" what you want.

You need to do this in both cases.

Then again, why bother with the tokens if you have XSS access as an attacker? I'd simply show the user a login prompt and take their password when they type it in.
> HTTPOnly cookies are safe from XSS attacks.

Not completely true - the attacker can not exfiltrate the token but they can still make malicious requests right there in the victim's browser via XSS.

What was their argument?
Short lived access token, and long lived refresh token.

Upon access token refresh and login, refresh token is also rotated.

Refresh token expiry is tens of days, access token some hours.

Their opinion is that this is enough security.

IMO refresh token is vulnerable being stored in localStorage, and relying on users logging in and/or triggering token refresh to rotate refresh token is not really that great.