0

I have been researching how best to implement authentication in a React/Next.js application - specifically, how to store authentication tokens in a manner which is practical, while maintaining a needful emphasis on security. There is some existing debate about this topic on SO but as far as I can see, none offer concrete solutions.

Having spent much of yesterday and today trawling the internet for answers, I came across the following:

  • Local Storage API. I found that some basic guides suggest the use of localStorage (though many rightfully advise against it). I do not like this approach because data stored in localStorage could be accessed in the event of an XSS attack.

  • Web Workers. If the token is stored in a web worker, the user will not be logged in if a new tab is opened. This makes for a substandard and confusing user experience.

  • Closures. Same as Web Workers - there is no persistence.

  • HttpOnly Cookies. On the one hand, such cookies cannot be read by JavaScript so it's not prone to XSS. However, on the other hand, we now have to deal with CSRF, which is a new debate altogether: how does one implement CSRF tokens with an SPA + REST API?

While the use of HttpOnly cookies seems most favourable, implementing CSRF in an SPA seems unconventional and perhaps experimental, contravening the maxim of not "rolling your own" when it comes to security. I'd rather use a proven method if one exists.

With SPAs being all the rage nowadays, I am surprised that it's proving so difficult to find a consensus (or even better, a library) for such a prevalent scenario.

How is everyone else doing it?


Update: After some thought, I wonder if localStorage is really that bad if there is a strong CORS policy? If there happens to be an XSS vulnerability, couldn't the attacker start sending requests from within the browsing context anyway, negating any perceived benefit of using cookies and CSRF protection?

Obvious_Grapefruit
  • 399
  • 1
  • 2
  • 12

1 Answers1

-1

Your comparison is a bit confusing... When you talk about SPA authentication, you need a solution that alows you to store authentication tokens. The main purpose of Web Workers and Closures is to run code, not for to store authentication tokens. You can write it down as a hard coded variable but it's not its purpose and this is why a new tab won't identify it.

So we're left with Local Storage and Session Cookies. Before SPA and client side rendering, we used to only have server side rendering and cookies. This is when HTTPOnly was invented to make it harder to steal session IDs and users' identities. When client side rendering was invented, stateless APIs were invented. These APIs do not use session IDs but Tokens instead, such as JWT. It means that the server do not save any information about the user in a session that is identified by a session ID. Instead, JWT tokens contains the signed information within the token itself, and the server do not remember anything and reauthenticate the user in each request. There is also a hybrid approach of tokens that are saved in NoSQL DBs in the server side such as Redis, to make the authentication process faster.

But the bottom line is that HTTPOnly cookies are used with stateful APIs that use sessions, and LocalStorage are used with stateless APIs that use tokens. You can also use it the other way around (cookies with tokens, LocalStorage with sessions) but its "less natural".

As for XSS, HttpOnly mechanism in cookies makes attackers' life a bit harder, but even if it is used, attackers can still do a lot of damage with phishing for example. So its not critical as this is just a compensating control and not a main mitigation in any way, so you can safely use LocalStorage. Furthermore, cookies are prone to CSRF attacks where LocalStorage does not. So both options are valid.

You can read about it some more in here: What is the difference between localStorage, sessionStorage, session and cookies?

Gil Cohen
  • 796
  • 6
  • 11