So, as the title says I am using Django Rest Framework, combined with React.
I authenticate users using token authentication. Now I am facing a problem. When I reload a page (by pressing F5 key, for instance) all the state is gone, and I can't save the token in such cases, requiring user to sign in once more.
I thought about storing the token in a cookie, but that doesn't seem very safe.
There are other questions like this, but no answer really explains how much of a security risk this is. I figure it is quite high, since having the token seems to be enough to authenticate as someone to the back-end.
So, my question is: Is my assumption that it is not safe to store my authentication token in a cookie true?
Note: I am thinking about switching to session based authentication, but I'd rather safe me the work and keep the token authentication.
Request an Auth Token in Django REST FrameworkThe Django REST Framework will provide an endpoint so that the user can request a Token for authentication with their password and username. It won't handle GET requests. It will inform you to use POST request with username and password.
JSON Web Token Authentication Unlike the built-in TokenAuthentication scheme, JWT Authentication doesn't need to use a database to validate a token. A package for JWT authentication is djangorestframework-simplejwt which provides some features as well as a pluggable token blacklist app.
After verifying the credentials, the server issues two JSON Web Tokens to the user. One of them is an Access Token and the other is a Refresh Token. The frontend of your application then stores the tokens securely and sends the Access Token in the Authorization header of all requests it then sends to the server.
JSON Web Token (JWT) Authentication This is a new and popular standard that works similar to TokenAuthentication except that it does not need to save tokens in the database.
I forgot my old answer was still up on the internet getting some traction... and it's partly wrong, as I realized later.
I thought about storing the token in a cookie, but that doesn't seem very safe.
It's safe enough, if done correctly. Yes, the cookie will still be readable by anyone having physical access to the system. More on this below.
Let's make one thing clear, It is absolutely necessary to store some data on client-side (browser in this case), and send this data with API calls to authenticate users. Let's call this data "token".
When you send this token in API calls, anyone having physical access to the system can view it. Also, there's no point of encrypting it because...
What are the options? Honestly, let it be. Most websites work like this (almost). Unless the website holds some very sensitive information. In that case, look into time-based passwords, hardware-based passwords, bio-metrics maybe? These methods mostly passes on the responsibility of safely keeping the keys to user.
You can of course, make it more secure. Here are some tips:
With that in mind, let's talk about storing the token.
We just need to make sure other websites, malicious scripts, and software cannot access the stored token. (The user can always read the token, as mentioned above.)
You can either store it in cookies
or localStorage
. Both work fine, but localStore
is designed to store larger data. Cookies
can store upto 4096 bytes of data - which is enough for storing token. Cookies
also help when working on SSR (server-side rendering). Though, it can get tricky to handle cookies in React. (Tip: Try next.js, it has built-in support for cookies and SSR with React.)
You can also specify expiration time in cookies, if that helps.
TL;DR: Using Cookies
is perfectly fine. Just use it properly.
Thanks to @ShayanSalehian for pointing this out: LocalStorage is subject to XSS and cookie is subject to CSRF. So I think using cookies + CSRF is the most secure way even in TokenAuthentication for storing tokens on client...
This is something I had to deal with as well. Lost a few nights' sleep in the process.
Disclaimer: I'm not any expert in security. Just a bit obsessed (read: paranoid).
Short version (to answer your question): I finally ended up using window.localStorage to store the token. Though I'm not convinced myself that it's the best thing to do, but it's not just about the "storing" part - read long version to understand more.
Long version: First, let's clarify a few things. React is more like a mobile app than a webpage/website. I'm not talking about React Native - I mean React.js.
Why am I saying it's more like a mobile app than a website? Traditional websites usually use session based authentication, for which browsers/servers are typically prepared. It's a no brainer and seamless task apparently.
In a mobile app (or client-side standalone app), you need to maintain some sort of token to essentially tell the server "Hey, it's me! I visited a while ago. Here's my identity card. Let me in, please?". The problem is, it's hard to keep the token secure at client end. Android itself didn't provide any secure way to store authentication token until Android v4.3. That too wasn't secure enough, so they introduced hardware-backed keystore a while ago. This is the reason why some apps didn't (and still don't) work with rooted devices. Read more about this here: https://stackoverflow.com/a/19669719/3341737
Compared to a React/standalone web app, Google (somewhat) controls Android client-end. It's comparatively easier for them to implement hardware-based keystore. In case of web app, there are tons of browsers, with hundreds of versions and whatnot.
Coming back to window.localStorage. Similar to Cookies, localStorage is isolated for each domain. Since it's a newer API, it's designed in a better way than good old Cookies.
There's no point in encrypting the key (you may obfuscate it though), as you'll need to store the decryption key somewhere locally as well. So if someone can get access to the token, they can access decryption key as well.
Second aspect of this issue (and why "storing" isn't the only problem) is - from whom do you really want to protect the token?
Why not? Because you'll need to send the token with each request - and data sent with every request is available in browser network inspector. So regardless where and how you store the token, it can be stolen by someone with physical access to PC.
Why not Cookie? Two reasons (1 actually):
window.localStorage.setItem('key', 'value')
). Also, the maximum size restriction is much higher as compared to Cookies.Thus, window.localStorage seems a feasible option to me. Enlighten me if you have a better solution.
That being said, this does not mean you can't improve the security. Here are a few suggestions:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With