Note: This question might sound like a duplicate, but all other similar questions did not take into account (mobile apps, iot's, web, 3rd party usage). Specifically, in dealing with the clients together with cookies.
I'm building a REST API (laravel based) that is to be consumed by multiple clients like web, mobile apps & iot applications. Personally, I'm decently experienced in traditional MPA web applications. So I already am aware of the major security concerns and have dealt with them acceptably so far.
However, this time I need to make a SPA web application. Correct me if I am wrong, but in this type of situations separating the server from the frontend is a good practice, since the web SPA is not the only client benefiting from the API. Which itself, is kinda the point of RESTful API's in the first place.
I have spent the past 2 weeks extensively researching the proper way of authenticating/authorizing REST API applications. The more I researched, the more the dilemma (which I will explain below) got complicated.
Given the following conditions/requirements:
- Each request made to the API must be run through a database authentication/authorization check. So stateless JWT tokens are out of the question.
- Some kind of a token based authentication must be implemented. I don't think it's a good idea to ask for credentials at each request.
- Some kind of a "remember me/keep me logged in" mechanism has to be implemented. So if the user logs in, chooses to be remembered and then closes the browser, he should stay logged in the next time he opens the SPA, given the usual expiration/validity problems are dealt with on the first "next" request. So just storing in JS context memory is also out of question.
- Other clients like native mobile apps should not be forgotten. Also, I am not sure about this, but I think dealing with cookies in mobile/iot apps is pain in the a**.
Basically, what I came to understand is that it basically boils down to 2 options for persisting the "access/bearer token" or as known traditionally: the session.
1) Bite the bullet and go with the good old httpOnly, HTTPS secure cookie way
- Immunity to XSS(*Some terms and conditions apply).
- Needs XSRF protection. Therefore, needs to have a common backend (or at least a proxy server). And I don't even want to imagine how this is going to account for mobile apps/iot's with the even added headache of cookies. This also means that in the future the API cannot be consumed by 3rd party applications.
2) The modern JWT way
- Immunity to XSRF. Which means the API is ready to be consumed by both 1st party and 3rd party consumers. This also makes it easy to implement across most clients (web, mobile apps, iot).
- Prone to XSS. Because it somehow needs to be stored in webstorage to meet the requirements mentioned earlier("Keep me logged in" to be particularly pointy). Especially since user input is accepted and frameworks like Vue.js is used in the SPA.
On one hand, you have Microsoft employees suggesting to completely drop out cookies with SPA, i.e.: Forget XSRF and deal with XSS. Since this is kind of the purpose of REST API's and since XSS is the elephant in the room that has to be dealt with eventually. They also mention how this makes CORS easier for 3rd party applications to consume the API.
On the other hand, you have other experts (like Auth0) suggesting to avoid dealing with XSS, and to deal with the easier to handle XSRF.
Personally, I am leaning towards using JWT's and dealing with XSS. Maybe because of keeping RESTful or maybe because I just don't want to handle cookies in other clients(also how the server is going to deal with XSRF in mobile app/iot's).
My reasoning is to just store JWT in localStorage, and hope for the best. Not forgetting to implement XSS protection measures in the first place with other possible combinations like CSP. Is my conclusion going the right way? Is there something I'm missing out? Is there something I got wrong?