Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect expired user session in a react app?

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!

like image 280
travelboy Avatar asked Mar 23 '17 14:03

travelboy


2 Answers

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.

  1. 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.

  2. 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!

like image 68
Vlad Avatar answered Oct 21 '22 00:10

Vlad


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).

like image 27
Hashbrown Avatar answered Oct 21 '22 00:10

Hashbrown