I am building an app in Reactjs. I have to make fetch call, after verifying the access_token. On signup, access_token are acquired from back-end server. But, where to store thes
Available options and limitations:
There are 2 types of options for storing your token:
sessionStorage
and localStorage
. Data stored here will always be available to your Javascript code and cannot be accessed from the backend. Thus you will have to manually add it to your requests in a header for example. This storage is only available to your app's domain and not to sub domains. The main difference between these 2 mechanisms is in data expiry:sessionStorage
: Data available only for a session (until the browser or tab is closed).localStorage
: Stores data with no expiration date, and gets cleared only through JavaScript, or clearing the Browser cache/Locally Stored DataYou have to consider 2 aspects when designing your authentication mechanism:
For security concerns, OWASP does not recommend storing sensitive data in a Web Storage. You can check their CheatSheetSeries page. You can also read this detailed article for more details.
The reason is mainly linked to the XSS vulnerability. If your frontend is not a 100% protected against XSS attacks then a malicious code can get executed in your web page and it would have access to the token. It is very difficult to be fully XSS-proof as it can be caused by one of the Javascript librairies you use.
Cookies on the other hand can be unaccessible to Javascript if they are set as HttpOnly
.
Now the problem with cookies is that they can easily make your website vulnerable to CSRF. SameSite
cookies can mitigate that type of attacks. However, older versions of browsers don't support that type of cookies so other methods are available such as the use of a state variable. It is detailed in this Auth0 documentation article.
Suggested solution:
To safely store your token, I would recommend that you use a combination of 2 cookies as described below:
A JWT token has the following structure: header.payload.signature
In general a useful information is present in the payload such as the user roles (that can be used to adapt/hide parts of the UI). So it's important to keep that part available to the Javascript code.
Once the authentication flow finished and JWT token created in the backend, the idea is to:
header.payload
part in a SameSite
Secure
Cookie (so available only through https and still availble to the JS code)signature
part in a SameSite
Secure
HttpOnly
CookieAuthorization: Bearer your_token
You can set an expiry for the cookies to meet your app's requirements.
This idea was suggested and very well described in this article by Peter Locke.