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 these access_token. Is there any way of making these access_token global, so that all component can access it. I have used local storage, cache and session storage, but those are not advisable. Held up in this issue for past few days, any solutions for it. Thnks in advance.
-
1Are you using redux? – sundar Feb 26 '18 at 07:57
-
1.secure:http only cookie from server, 2.common: redux/cookie/session – Josh Lin Feb 26 '18 at 07:59
-
yea, i am using redux – Thananjaya S Feb 26 '18 at 08:03
-
1You can bind it to the window object or you can put it into the initial state of your redux store. – trixn Feb 26 '18 at 08:10
-
4but on refresh, access_token will be null or undefined! – Thananjaya S Feb 26 '18 at 08:12
-
Rails server will provide access_token after validating users email and password. On receiving the access_token, refresh_token and expires_token, where to store them. I am using redux, redux-thunk middleware. – Thananjaya S Feb 26 '18 at 08:29
-
You could store all that info in a signed JWT token(https://github.com/auth0/node-jsonwebtoken) and save that in localStorage or as a cookie, but you could also store each token in the cookies/localStorage – Marco Feb 26 '18 at 08:42
-
yea but, it's not advisable right. – Thananjaya S Feb 26 '18 at 12:11
-
@ThananjayaChakravarthy I am also on a same boat. Although I could manage to get my token and store through redux, which is useable throughout the app. However, as soon as someone refresh the app i.e. F5 or hard refresh (command + r for mac). The whole state is go went gone! Any better solution for this problem is appreciated. – codebased May 30 '18 at 23:18
-
1@codebased, I am using `firebase` for storing `access-token`. – Thananjaya S Jun 04 '18 at 08:17
-
4I think localStorage is totally fine. If you are worried, use some simple auth token (JWT can't be expired) and give it a short expiration like 1 hour. Also if you wanna protect some crucial actions (like payment or sth) then make those password required. – Sean Magyar Jun 15 '18 at 21:54
-
React router latest version allows to store data's in their location state. – Thananjaya S Sep 07 '18 at 06:02
2 Answers
Available options and limitations:
There are 2 types of options for storing your token:
- Web Storage API: which offers 2 mechanisms:
sessionStorage
andlocalStorage
. 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 Data
- Cookies: Automatically sent to your backend with the subsequent requests. Expiry and visibility to your Javascript code can be controlled. Can be available to your app's sub domains.
You have to consider 2 aspects when designing your authentication mechanism:
- Security: An access or identity token is a sensitive information. The main types of attacks to always consider are Cross Site Scripting (XSS) and Cross Site Request Forgery (CSRF).
- Functional requirements: Should the user stay logged in when the browser is closed? How long will be his session? etc
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:
- Store the
header.payload
part in aSameSite
Secure
Cookie (so available only through https and still availble to the JS code) - Store the
signature
part in aSameSite
Secure
HttpOnly
Cookie - Implement a middleware in your backend to resconstruct the JWT token from those 2 cookies and put it in the header:
Authorization: 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.

- 13,430
- 7
- 40
- 80

- 2,050
- 1
- 15
- 25
-
So in step 3 how would u extract the cookie from the browser and append it to the header? – asus Aug 08 '20 at 16:13
-
Step 3 is for the backend service. It will receive 2 separate cookies. So instead of reading one cookie, it will have to check 2 of them. The browser is not involved in this step. – Anouar Aug 09 '20 at 19:18
-
1I get that. However, you must pass the cookies to the backend. If you use axios, how do you extract an httpOnly cookie in the ui, append it to an `Authorization` header? Currently, I can simply send the cookies in a regular `headers.cookies` using `withCredentials: true` but I don't know how to send them in Authorization headers – asus Aug 09 '20 at 23:35
-
You don't send them in the `Authorization` header. The `HttpOnly` cookie is not visible to your Javascript code (and that's the goal of this approach). In your backend middleware you will receive the 2 cookies and merge them in the `Authorization` header. – Anouar Aug 10 '20 at 08:47
-
So you mean you would merge the cookies on the back end into the authorization header **before** they can be consumed by various controllers? – asus Aug 10 '20 at 16:32
-
@Anouar what if we keep access token in memory(with a short expiry time) and not in cookies. Are we still vulnerable? And we only keep a refresh token in an HTTP only cookie. – wayne Jul 25 '23 at 11:47
-
@wayne none of the mechanisms available in the web storage API provides a configurable expiry time. The idea here is to avoid storing such token in (browser) memory/storage. – Anouar Jul 28 '23 at 15:52
Although late to the party, I feel like sharing my thoughts on this topic. Anouar gave a good answer, including the http-only cookies that are considered save against XSS, pointed out the CSRF vulnerability and linked the article by Peter Locke.
However, in my case, I need the application to be 100% stateless, meaning I cannot use cookies.
From a security point of view, storing the access token in a persistent location (like localStorage, window,..) is bad practice. So you could use either redux (or react.js built in state/context) to store the JWT in a variable. This would protect the token from the mentioned attacks, but null it once the page is refreshed.
What I do to solve this is using a refresh token, that I store in localStorage (you may use session storage or similar if you like). The single purpose of that refresh token is to obtain a new access token, and the backend makes sure that the refresh token is not stolen (e.g. implement a counter that gets checked against). I keep the access token in cache (a variable in my app), and once expired or lost due to a reload, i use the refresh token to obtain a new access token.
Obviously this only works if you also build the backend (or at least if the backend implements refresh tokens). If you deal with an existing API that does not implement refresh token or alike, and saving the access token in a variable is not an option for you (due to null on reload), you could also encrypt the token with an application secret before you save it to localStorage (or sessions storage, or...yea you get the idea). Note, that decrypting the token takes some time and can slow down your app. You may therefor save the encrypted token to localStorage (or...) and decrypt it only once after a refresh to then keep it in a state/redux variable until you refresh again/decrypt it from localStorage again etc.
A last word on this topic: Auth is critical infrastructure to an app, and although there is an obvious difference between a fun game and an online bank (you might want to be "paranoid" about that bank, while only "concerned" about the game), answers like "localStorage is totally fine" or "what could happen in the worst case? expire after 1hour" are dangerous and simply wrong. Machines can do alot of damage in a few seconds, and you do not want to leave that gap open. If you are too lazy to secure your app, maybe you want to use an existing solution instead of building your own.
That said, JWT / token auth is fairly new to the game (a few years, but not as mature as other topics in dev). It takes some time and effort to find a working solution, but let us keep building secure software instead of flooding the web with quick hacks.
Best, & happy coding.
-
Great awnser exactly what I needed to hear for my laravel backend, passport alrealy uses refresh_tokens and I didn't know their purpose. – Danys Chalifour Mar 04 '21 at 11:24
-
6Good answer but you should never store the refresh token in local or session storage. The server is the only one that needs to read the refresh token and you can do that by storing it in cookie with HttpOnly and secure set to true – Udendu Abasili Dec 10 '21 at 12:55
-
I agree Udendu Abasili. My answer is focused on a 100% stateless approach. That is why I decided to store the encrypted token in local or session cookies. However, I also would generally recommend to use (encrypted) HttpOnly cookies if possible. – randmin Jan 05 '22 at 18:12
-
I meant "local or session *storage*", obviously. Just realized I made that mistake in my preceeding comment. – randmin Feb 14 '22 at 17:21
-
1You said "you could also encrypt the token with an application secret", where do you store the secret then? Encrypting won't solve the problem, just propagates it. – Sam Feb 15 '22 at 13:16
-
1You also said "the backend makes sure that the refresh token is not stolen". There is no good way to do this, a attacker can figure it out by trial and error. – Sam Feb 15 '22 at 13:23
-
The secret must be stored on the server, obviously. Also, a counter on the server side would recognize a stolen refresh token. What's your point? Please elaborate – randmin Feb 22 '22 at 07:14
-
1@randmin can you please explain more how to implement this counter and how this helps to check if the token was stolen? – Leonardo Rick Jul 31 '22 at 13:11
-
@LeonardoRick If you increment a value on the server anytime the token is used, and make the client include the current counter value on every successive request the following would happen: An attacker would increment the counter on the server by using the token, and when the "victim" (as in authorized user) passes the current counter value, it would not match the counter on the server anymore. You could then handle this case server side (e.g. invalidate the token and inform the user) – randmin Jun 17 '23 at 04:16
-
@randmin what if we keep access token in memory(with a short expiry time) and not in cookies. Are we still vulnerable? And we only keep a refresh token in an HTTP only cookie. – wayne Jul 25 '23 at 11:49