How to detect expired user session in a react app? - reactjs

I am developing a REST API based on Node / Express and a frontend for it based on React / Redux. Users can login (which gives them access to additional functionality) but they can use basic functionality also without logging in.
When a user logs in, the client makes an HTTP call with the credentials, the server creates a session and returns a user object (user_id and some other data) as well as a session cookie. The React app saves the user object in its Redux state. In subsequent HTTP calls, the user is authenticated through the cookie.
When rendering the user interface, the React app determines whether it is logged in or not by checking for a user object in its state. This is used to grey out some buttons which are only available to logged in users, or to hide the login link when the user is already logged in.
The problem
It could occur that the session expires, or that the user logs out in a different browser tab. The React app has no way of knowing this and thinks it is still logged in (i.e. app state mismatches reality), leading to wrong UI display.
What pattern to solve this?
Put a hook on all Ajax calls to check for 401 and update the
state?
Return session state in HTTP headers (and then?)
A Comet pattern for the server to notify the client that it has been logged out? (not a REST API anymore then)
Additional calls before actual API calls to make sure user is still logged in? (seems wasteful)
And how to deal with this once the client detects it is no longer logged in during an ongoing operation? I'd prefer to handle this in one place rather than all functions making API calls...
I'd be thankful for some best practice!

There are two straightforward ways to deal with this issue in a React application that I can think of. Both inspired by a colleague of mine few days ago.
Use SSE (server-side-events) technology to PUSH notifications. As you correctly pointed out, this makes your API less pure. This approach should be quite an acceptable sacrifice where flawless UX is required AND/OR your server might need to push other notifications to the app.
Establish a short term timer somewhere in your client app (e.g.: setTimeout(...)) that makes periodic calls to a "ping" API endpoint that will return current user/session information. This approach will impact UX for the duration of timeout, often negligible, and is commonly known as polling.
Hope this helps!

As an alternative to the naive polling, you can make it a little smarter by adding an endpoint that lets you know in how many seconds timeout is set to occur for the session at that point in time.
Then ping just before that time (instead of at a certain poll-rate) and update accordingly.
Logging out in another tab would return with an invalid token so would be picked up, too, but not as quickly if this is your main concern.
For this you could use broadcasting to let the other tabs know immediately (or use sessionStorage's change event to simulate a broadcast on unsupported browsers).
Otherwise the best way would be to implement a ServiceWorker; these can handle all requests for your app to the server. It's a centralised piece of code separate from your app that can broadcast to all tabs that a session is lost the moment it sees that one of its requests was rejected, and you can efficiently naively poll from this one place (instead of in each individual tab's runtime).

Since I am using token from the API Server that is valid for a specific period of time. So in addition to setting token in session storage I was thinking of setting up another session storage variable that stores the timestamp at which the token was generated. Then, in my js code I plan to add the validity period (say, 3600 seconds) and check if the token is still valid or not. If it is valid then the user session is valid else it is invalid.

Related

Can the client modify react component state?

I'm building an admin page for an application and have a state value 'authenticated' that flips from 'false' to 'true' after a successful login (which is authenticated on the server) which then shows the actual admin panel.
Are component state values safe from tampering by the client? Basically, if the client can modify my 'authenticated' state value to 'true', they can skip the login and go straight to the admin panel (which I obviously don't want).
I read that React Dev Tools allows the client to modify values yet everyone says "validate on the server" but I am validating on the server and updating my state accordingly, if the user is approved. If it is not wise to have a state value manage this, what is the right way to conditionally show the admin page after a successful, server-side authenticated login?
I think this is an important question since tampering with state values in a React app can have huge negative consequences on data integrity within an app/database.
TL;DR: Either require an authentication token with every request or require authentication through a session.
Never trust users always. One potentially big issue is if you "hide" admin actions behind the admins page without requiring authentication.
For example, assume the backend server uses a REST API to accept commands. In the admin panel you get links to administrative actions like a button 'Delete Everything' that sends a DELETE request to server.net:8080/api/admin/everything without requiring any authentication. If you're a user, you can find that in the code potentially and then send a DELETE request to that address from anywhere without any repercussions.
We'd never give administrative privileges to anyone who would want to delete everything... Because we'll never untrust someone. Right?
Worse, someone might find the server and fuzz some inputs to it, and oops! They manage to delete everything (or even worse, GET everything stored in the database). This wouldn't be hard to do, especially if the server you use to authenticate is the same server you use to issue commands. History has proven "security through obscurity" to be a very bad paradigm. Every action should be authenticated, even if it seems like the actions will be hard to find.
Generally, providing a JSON web token or some other form of authentication token and having the user send that with every request is a good start at least, especially if it has an expiration date. The token would be provided through a separate request with valid credentials.
Sending a token with every single request obviously isn't ideal. There are a couple of other things to try. For servers using PHP, you can probably trust sessions (though very many people who know more than me would probably disagree). In more modern cases, you could try to use Web Sockets, requiring the token after connection. Then only after authentication with the token do you allow the user to make administrative requests.
That way, even if a user knows the exact command they can send to perform any action, the server won't let them without a current session or token. Unfortunately, unless you're already using Web Sockets or depending on a session, it will likely require a lot of changes. I'd consider this to be critical though.
It is always possible to tamper values in the front-end, there is no way you can rely solely on the front end to ensure security.
Your best approach is to implement some form of authentication and authorization on your backend. In this way, even is some users pretend to be admin, they will be blocked when you do the next request to the server.
Perhaps if you can send more information regarding your problem, we can think of a more specific solution.

Mobile App authentication for admin actions

I am developing an application where users are playing a game and upon completion their results are sent to my back end through a POST request. Since I do not want this POST request to be done manually by someone who finds this endpoint (and mess with his results), I need a way to restrict it so that it can be done only through the application. However is it safe to hardcode a token that provides this access?
What is the correct way to go around this problem ?
I would not recommend to use hard-coded tokens, if the token gets compromized, you have to change the server as well as the client.
I would recommend some sort of auth mechanism as JWT with ssl with one rudimentary username/password system.

Does authentication differ at all when creating an app with angular?

In a regular web app, when someone logs into the system they simply save an encrypted cookie that gets send on each request and the backend decrypts the cookie and uses the e.g. user_id/guid to lookup the user.
How do things differ when authenticating with a angular app?
Is there anything else to consider or it is basically the same process?
We use more or less the same mechanism.
Access to the application as a whole requires authentication - that is unless you're logged in, you don't get any of the javascript experience at all. This could make the login / login failure much less wizzy for the user, but in our authentication provider it's fine.
Part of our auth mechanism means the list of roles that the user has is a data object available within the browser. The javascript code uses this to decide which buttons / menus etc. are displayed. I checked with our security guy and he said something like "Well, it's a kind of direct object reference issue, but as long as each action is authorised properly, you're probably ok." So it's possible that a user could hack data values and change what they can see, but because of the next bit, they can't break our data (or see stuff that they shouldn't).
Each service call our javascript makes is authenticated and authorised. That is, the javascript call will fail if the auth token is missing or bad, but also, we internally match the auth token with a user and a set of permissions, and only execute that if the user is authorised to do so. (Note that this is good practice whether you're using Angular or not). Also note that this applies to GETs as well as POSTs - we don't want to give them data they should not see.
It gets much trickier if your API is hosted separately from your Angular site.

What is the best approach to work with data while using token based authentication

I am building an sample application that lets user store comments.
I've created the registration and login process. When the user registers, his details are stored in a MySQL database and a token is returned to the browser. Now he can access the Profile page.
When an existing user logs in he is redirected to the profile page. The profile page is accessible only when a user registers or logs in.
After logging in, I want to show all his comments if he has already added them.
My frontend is in Angular and backend use Laravel. For authentication I use Satellizer.
I want to know, what is the best approach while playing with data, considering the fact that the user will add, edit his comments. Should I use localstorage and store data in a key value pair or should I create a json file which gets updated everytime the user adds a comment or makes a change.
I wanted to know what is the most efficient way to deal with data from server so that the application is fast even when it scales to a 10000 users and lot of data for each user.
Thanks
You should be updating it on the server when changes are made rather than only relying on localstorage. You can use localstorage to cache, but it should only be for immutable data, it shouldn't really be used for data that is going to change.
So in this case you'll be adding and updating new comments via your API (ideally a RESTful one!). Once you've made a change, you could store the comments locally and only update them when the user makes a new comment, however you'll quickly run into issues where the data is invalid on different clients. (i.e. if you update the comments on a different computer, the other computer won't be aware).
Alternatively, you could cache the comments and then simply ping the server to find out if new comments have been added. This could be using a HEAD request for example to check the last modified date on your comments resource.
You can store comments data locally on user browser, but you should properly manage it.
I don't how much load your server will have and if the time invested now worths it.
You can fetch comments and store them locally
User adds a comment, then you update locally and send a request to the server
You need to track the request response, if requests fail so notify user and remove comments from local.
if request was successful so you can continue on your way.
** facebook uses this "success first" approach
user does an action, and he see it happens instantly, in the background it could take few seconds, only if it fails they will notify you.
** look at their commenting process, when you comment, it appears instantly, no loading... but in the BG the load happens.

AngularJS + Socket.IO + Authentication

I am curious how others are solving the following problem...
I have an angular application that requires user authentication. The user must log in to the system to make requests. The user must also be authorized to create a socket.io connection.
When the application first starts up I must determine if the user is already authorized. I was planning on looking in sessionStorage for a user object/token. Does that make sense? And if the user is not authorized, the application will make a request to get the current user. If/When that fails, a 401 error is returned and angular intercepts/prompts for a username/password.
Given that there are two different code paths for authentication (check sesssionStorage vs make a request and wait for the response) how do you trigger the requests for all the other information that is required for the application? Do you emit/listen to a LOGIN event that gets broadcast in both scenarios?
My plan was to wrap the socket.io connection attempt and the ".on(...)" calls inside of the LOGIN event, does that make sense?
And if you want to listen to socket.io events or grab information from the server in a controller that is loaded after the LOGIN event has fired, how do you trigger the data from being retrieved from the server?
Sorry for the long winded questions, but I've hit a road block and I'm wondering how others are managing all the authentication and different pieces of information that is required to get from the server.
Ok, I guess let's go in order of question asked.
Does it make sense to use sessionStorage to hold user auth info?
Yes. You will need to decide between local/session Storage depending on how you want it to work. We decided we wanted the session to still be active for the time period that the backend recognizes, so even if the user closes the browser and reopens it, they will be logged in, and so we opted for localStorage instead of sessionStorage.
How do you trigger the requests for all the other information that is required for the application? Do you emit/listen to a LOGIN event that gets broadcast in both scenarios?
After login, we redirect the user to the "landing" page (route). All of our route/state changes wait on a resolve function which is doing the session auth. We only store the session id in localStorage. After the successful state change, the controllers that go with the newly loaded views start requesting data from our services. All of our controllers are designed to load data on init. So no, we do not use events. It feels like events should be used only as a last resort - and that is also the impression I get from core Angular devs since I get chastised for event usage in pull requests :)
My plan was to wrap the socket.io connection attempt and the ".on(...)" calls inside of the LOGIN event, does that make sense?
Maybe. I am not using socket.io outright, but instead have been experimenting with atmosphere (mainly because we had a java backend requirement). I do initiate the connection in the login success handler. But the general atmosphere event handling I have put into an application-level controller that is on <body>.
And if you want to listen to socket.io events or grab information from the server in a controller that is loaded after the LOGIN event has fired, how do you trigger the data from being retrieved from the server?
I could imagine (again using an app-level controller, or a service, or in my case, likely both) a function that returns the socket.io connection. A controller that has come into being could grab the socket.io stuff on init, and setup the listeners for the events that it is interested in.
My advice is to get all of your session and auth stuff worked out first, especially with regard to how you are going to do routing. Once all of it is working to your satisfaction, then add the socket.io stuff in. I realize that this might not be possible in all cases because perhaps you need something from the socket.io connection that is critical to your app even at an early stage.

Resources