react-router auto-login in the onEnter hook - reactjs

In all the react-router examples for the onEnter hook, the hook is synchronous. In the issues it's recommended to keep it that way. What's the idiomatic way to log someone in while inside a hook?
User-story:
Client has a localStore token
Client navigates directly to example.com/mustBeLoggedIn
Before going to that page, I'd like to check if they have a token, if they do, attempt to gain authorization. If authorized, continue onto route
Should I just use a HOC instead of onEnter?
I currently have it working, but I know it's not recommended, and seems very brittle, for example using an immutable store causes the same issues as this issue: https://github.com/rackt/react-router/issues/2365

There are a number of ways to solve this challenge, but I agree with the recommendation that calls in onEnter should be synchronous. Here are two ways to solve this challenge.
Option 1: Don't Validate the Token on Page Load
It is arguably the case that the browser should not validate the existing token at all. That is, the browser should assume that the token is valid and try to load the route as defined.
On an API call failure response from the server (where the actual authentication and authorization is really occurring), your app can handle the need to re-authenticate any way it chooses: redirect to a login page, present a login dialog, etc.
The advantage of this approach is that it will work across all routes that employ this logic without having to specify the routes that need it individually.
Option 2: Use an HOC (recommended)
As you suspected, an HOC is probably the best way to go. Your router would attempt to render something like this:
<EnsureAuthorized checks={myCheckFunction} Component={MustBeLoggedIn} />
This kind of flexible HOC could optionally run custom authorization checks in addition to the required authentication checks (like user roles), and render the component provided only when the authentication and the checks succeed, and then handle failures in a consistent way (e.g. rendering a login component or redirecting the user to the login page or showing a 403-type message, etc).

Related

Apollo caching with React redirect doesn't get new items

I am using Apollo Client.
There's a route /restaurants/${restaurant_name}/places where it lists all the places for concrete restaurant_name.
Let's say I am on the /restaurans/france_res/places route. On that route, I can add new place for it. I add it and when it's done, I redirect users with history.push to the following route - /restaurans/france_res/places/place_name.
Now, if user goes to /restaurans/france_res/places route again (with no refresh, just react router's navigation), Apollo doesn't query the server any more and the places that route shows doesn't include the new one. This is because of the cache policy and it seems like the route /restaurans/france_res/places is already cached...
What could be the workaround for the following situation ?
using no-cache policy seems too harsh... Then what's the point of Apollo's caching policies in the first place ?
I don't use Redux, but I don't know how that could help me. There's a way with Redux, but it's not good.
Maybe, when new place gets added, I make user redirect to the route without history.push which will cause the hard refresh, causing queries to get executed again.
How do you handle situation like this ?

Login session in React

I'm creating a portal in React, and I need to allow login/logout of users, where if you are logged you can see some pages, otherwise you can't.
So far I've thought about having a variable 'isLogged' in the state of each component which need the user to be logged to be seeen, and pass the variable in the props among the these components.
Then, I saw I can also use the localStorage to save this variable (I'm ok with the fact that the user would remain logged as long as he will clear his chace).
The question I have is: is this ok, or it is not the right way to manage the session user (also considering security issues)?
If so, which is the correct one?
If it's useful to know, I'm not using Redux, and probably the portal will exploit only https protocol.
It may be very late but still You could try out this which is one of the best way to handle auth user
React - What is the best way to handle authenticated/logged in state?

Apollo graphql-connected React component isn't rerendering

I'm working on building an authentication mechanism over graphql, and I'm trying to figure out why a graphql-connected component isn't rerendering after relogin... for example:
At /users I have a react-apollo graphql-connected Users component that requests a list of users.
The server will return an authentication error if no token is provided; the component renders a <Redirect> to the /login route; after successful login, the Login component stashes the token and redirects back.
The Users component wrapper starts the graphql request and renders "loading..." in the meantime. When the graphql request succeeds, it rerenders and the users appear, yay.
If you Sign Out from that page, the Logout component at /logout discards the token then redirects back; the Users component's request gets the authentication error again and sends you to '/login'.
After another successful login, you're sent back to '/users'; again it starts a graphql request to the server (and renders "loading..."), but this time, when the request succeeds, the component isn't updated again.
I can see that the graphql request succeeds (and have watched in Chrome's debugger as the APOLLO_QUERY_RESULT action is handled by react-apollo's reducer and updates the state in the store).
I've tried to find where React is checking to see if the component's props have changed, but I'm enough of a React debugging noob that I haven't figured out where to find that code in the web inspector: maybe something I don't understand about how React is packaged for distribution.
I clear out the ApolloClient's store (by calling resetStore()) on both login and logout, since I don't want to accidentally reuse data from the other authenticatedness; however, removing these calls doesn't get rid of the problem. Interestingly (?), if I force the connection to bypass the cache by providing { options: { fetchPolicy: 'network-only' } } in the graphql() call, the problem goes away. (Not a viable solution - I'd like to benefit from the cache generally.)
I've built a stripped-down example: https://github.com/bryanstearns/apollo-auth-experiment
and you can see it in a CodeSandbox: https://codesandbox.io/s/m4nlpp86j (you'll probably want to access the running example from an independent browser window at https://m4nlpp86j.codesandbox.io/ because the sandbox editor kinda makes the web debug extensions act weird).
To fix this behavior, modify your graphql HOC to include notifyOnNetworkStatusChange in the options.
export const Users = graphql(usersQuery, { options: { notifyOnNetworkStatusChange: true } })(RawUsers);
I don't think you should have to do that -- I think data.loading is supposed to accurately reflect the status of your query regardless of that option being set to true, unlike data.networkStatus but it looks like it's a known bug.
As far as resetStore -- it doesn't actually wipe your entire store, but rather wipes away your store and refetches all your active queries. If you wanted to blow away your store, since you're already integrating Redux with Apollo, the easiest thing to do would be to create an action to do that.
You may also want to consider a session-based authentication mechanism, rather than relying on the client to persist a token. It's pretty simple to implement server-side, would not only involve less work on the client-side (don't have to remember to pass the token in with every request), and would let you keep your user logged in after they navigate away from the page.

React-router with Saga Server-side render redirect

The issue is that I have an initial fetch request that gets the query string from the URL and makes a request to get a specified product page.
The same logic and routing is used on the client side and server side.
The API request gets executed in redux-saga, but, when it fails (no matching product), the site is already on the /product route, and so redirect needs to happen.
On the client-side this is very easy, as it can be redirected dynamically using browserHistory or just window.location.href, but on the server, i would have to pass down the res object and use res.redirect and, possibly, use two different redirect functions with this approach.
The other solution is to catch this in a topmost fashion; on express index.js during ReactDOMServer.renderToString(component), and also on the client side endpoint when it fails - with different logic. For example, a 404 view with express redirect. But, because saga is not the topmost in hierarchy anyway, throwing this 404 and catching it in the uppermost context (express server) requires passing it up and up in a very "dirty" try/catch way.
Any suggestions how to tackle that in terms of correctness? I really don't want to have routing logic doubled up on express side, so I'd rather have it handled nicely with isomorphic code.
You are probably exposing your main state to be picked up by the front-end code. Any calls that are returned from sagas can update that state. We are using a set404() and set301() actions when redux saga does not return the data we want. These actions are triggered and they set return404: true or return301: true in the main state object. So before rendering our app to string we inspect that object. If any of these are present we return a relevant response from the server.

How to handle logged in status using React Router?

I'm a noob, starting my very first project with Node, Express, and React.
I got the authentication working, I have a Component that calls an action, which calls a store (or should), but this is where I get confused. I don't know where to go.
My LoginActions.login makes an api call to login the user, it comes back successfully and stores a cookie with the session ID. After that, how do I tell the UI to go to the dashboard? How do I make the UI KNOW that the user is actually authenticated, and if it's not, kick him out?
Where am I supposed to check for all that? Is it the store? The component itself?
Any help would be greatly appreciated.
You're not really "supposed" to do it in any specific way. React is more of a library than a framework. You can use it however you see fit.
One option would be to use react-router's onEnter function to verify logged in status and user it's replace method to redirect accordingly.
You could also have your components themselves verify logged in status and instead render your login form if not logged in yet.
Or you could even store your login form at a unique uri and handle all of the authentication via the server, using 302 redirects based on logged in status.
Up to you!

Resources