How to safely persist logged-in state of user in React website? - reactjs

I have a website that runs on example.com. The website makes AJAX calls to my backend API which sits at api.example.com.
I employ a double-submit verification strategy for my authentication.
The backend has protected endpoints which check the JWT token with each request. The JWT token is stored in a httpOnly cookie. It also contains the CSRF token.
Alongside the JWT cookie I also send a CSRF cookie which is not httpOnly.
Each request that the client makes must contain the value of this cookie in a special header.
So far so good, but, I want to make sure that the client does everything in its power to prevent users from making pointless unauthenticated requests. So in my React app I have declared a few private routes which check if the user is logged in and if they are not, the user is redirected to the login page. The logged-in state is kept in the Redux store.
The issue is that on a full refresh the Redux store is reset. So as I see it, my options are:
Option 1) Check the existence of a CSRF cookie
The way I check if a user is authenticated is by checking if they have the CSRF cookie; I also do this during the store initialisation. If they do have the cookie, they are allowed to navigate to the protected page. All subsequent requests on this page are still verified on the backend for a JWT and CSRF token.
Option 2) Check against the backend each time
I can create a simple endpoint on the backend that is used to check if the user is logged in. So instead of just checking the cookie, the client can submit a request to this endpoint and verify that the token in the cookie is still valid.
Option 3) Persist the Redux store
I could implement a persisted store (there are some libraries that do this out there) so that the initial problem is automatically resolved, i.e.: the logged-in state is preserved upon full refresh. However, this yields a bunch of issues with caching and token expiration and it may not be worth the effort.

Related

How to design React signIn proccess with NodeJS and sessions stored in cookies?

I have React signIn form and sessions mechanism implemented in NodeJs. In React I have protected routes only for authenticated users.
How should I check if user is authenticated. I have two ideas:
If user sign in for the fisrt time I can save this information in LocalStorage and then evrytime just check localStorage.
Send request to NodeJS server every time to check if user is authenticated.
Do you have any other ideas? Which solution should I pick?
I tried both options and second one is more UI unfriendly becasue I have to run loading state evrytime I am waiting for auth response. On the other hand, first option has also disadvantege, because I am based on token in LocalStorage which can be malicious.
Every time a request is made to an endpoint that requires authentication, the request should contain proof that they are who they claim to be.
The classic way to do this is by storing some sort of "Session ID" in a cookie or localStorage (client side), that you send along with every request.
Using a "Token" (e.g: JWT) instead of a "Session ID" is another popular way to handle authentication.
Check out this article for more information about both: https://dzone.com/articles/cookies-vs-tokens-the-definitive-guide
To return to your question, I'm not sure what you're worried about in regards to a "malicious Token in localStorage" (Or do you mean localStorage can be malicious?). But for a secure application you have to either:
Store something client-side
Require your user to provide credentials (username + password) for every request

React Query to store global state for user?

Is there a way to use react-query to store global state for user, if user is logged in or not?
Right not currently I am only storing cookie as bearer token and refresh token
And I am forcing react query to hit an API endpoint that checks if user has valid bearer token
So right now its making unnecessary requests and getting failed error response if use is not logged in.
What can I do to store user info when user is logged in, so that I don't have to make unnecessary requests to /verify endpoint?
There are several options to do it. But most common are:
Keep auth data in localStorage and before API call check if the authToken is not expired.
Keep auth data in the cookie and do the same
This will help you to avoid unnecessary requests and you will be able to make requests even after page reload/closing the browser tab

Authentication with JWT in HTTP only cookie without refresh token

The motto of the upcoming question is "I don't know what I don't know".
I would like to know if there are downsides or security risks with an authentication implementation.
Right now, I'm storing a JWT in an HTTP only cookie to send it from the client (React application) to the server (Spring Boot/Kotlin application). This removes the XSS vulnerability.
The JWT follows the basic principles (encoded secret, expiration date, issuer check, etc.). The server has servlet filters that check an existing cookie for validity on every request. When signing in via the client, the server responds with a valid JWT:
The client will send its cookie with every request, which is furthermore checked for validity by the server's servlet filters on every request. When these checks are positive, the user is authenticated with Spring Security.
As described above, the JWT expires after 1 hour, 1 day, or whatever is configured. That's why I need to refresh it some way or another. Now, instead of using a refresh token and placing it in the client's local storage, I decided to just make a small request to the server and create a new JWT, which is send back via the response again:
Again, when the refresh endpoint is called, the servlet filters will check for validity. So only an already authenticated user will receive a new JWT token that way. Some invalid JWT will not receive a new JWT.
I'm calling this endpoint from the client in an interval and therefore regularly extend the expiration date of the JWT inside the cookie.
What I'm aware of:
With the current refresh mechanism, an access token can be valid indefinitely (when the user is signed in regularly).
I also don't persist valid tokens or sessions in the database, so I can't really invalidate specific user sessions "globally" that way, as the cookie is the only source of truth. But this has nothing to do with the refresh token, I could create such whitelist/blacklist via the user ID instead.
If something really bad happens, I could still
...change the expiration date of all JWT to 0, so every authenticated user will be unauthenticated the next time he sends a request.
...or I could change the JWT secret, from which one no request will be authenticated anymore.
My question is: Has what I'm doing (replacing the JWT inside the cookie) any more downsides?

I'm authenticating the frontend app, using cookies session, but how to authenticate a user using ReactJS + Springbot?

I have to authenticate users in a scenario that involve a frontend(react) and a backend (springboot).
After working on it I realized that Springboot response include a set-cookie header, but actually the cookie session returned by Springboot is never set in the user-browser, so I asssume the cookie is set in the frontend app, which means that basically the frontend-app is the one authenticated, but no the user, make sense because the frontend is in the end sending the user/password.
How the people approach this scenario usually?, should I have a cookie session as well in the user-browser (so far is my thought)?, should the frontend store something different in the browser to keep track of logged in users?
Ideally I would go with Bearer token based authentication as I could use the backend for mobile applications as well.
Basically you would require to store the JWT in the local storage or key chain.
You could authenticate using JWT token. Get user details from token to use it in front end.
You need to set the session token in the localStorage. After storing it in localStorage you need to check session token on every protected route. If it's same as you have in backend it's good to go. However, if it has expired you need to run your logout api.

.net core, google sign in, and jwt cookies

I have a web app that uses Google sign in only as a way of signing in. I generate a jwt and it gets correctly to my app. But then I save the token on localStorage, which I am trying to move away from, so I want to send the token via a cookie.
Edit (as I was wrong with the root cause)
My back end properly returns the cookie as can be seen on the first image, when hitting the API's endpoint 'googleLogin'. However, I don't know how to then send that cookie on subsequent requests to my API so it is used to validate the logged user
My back end is .net Core, I generate the jwt there and also send the cookie, then I have set app.UseCookieAuthentication to check for that specific cookie, but it is not sent on subsequent requests so I am not able to authorize the user.
I don't know if it matters but the front end is a SPA using react

Resources