13

I'm having some trouble with authentication with redux and react router and am hoping for some clarification on how to best solve my problem.

I have a login component that when submitted dispatches the following action:

export const loginUser = (creds) => {
  return dispatch => {

    dispatch(requestLogin(creds))

    return fetch('http://127.0.0.1:4000/api/login', {
      ...
    })
      .then(res => {
        dispatch(receiveLogin())
        browserHistory.push('/admin')
        ...
      })
      ...
  }
}

The receiveLogin action updates the isAuthenticated flag in the state to true. My protected route has the following onEnter hook:

export default (state) => {
  return {
    path: '/',
    component: App,
    childRoutes: [
      {
        path: 'protected',
        component: Protected,
        ...
        onEnter(nextState, replaceState) {
          const loggedIn = //check state.isAuthenticated
          if (!loggedIn) {
            replaceState(null, 'login')
          }
        }
      }
    ]
  }
}

As you can see, I am passing the state in as an argument. This gives me access to the initial state from the server as well as on the client. However, after my login action happens, obviously the onEnter hook will still be using the initial state.

What I want to know is the best way to get the current state after the isAuthenticated flag is updated and use that in my onEnter hook instead. Or, is my approach totally flawed and should I be doing this a different way entirely?

1 Answer 1

26

I have found that using the onEnter hooks is not the best approach in my applications for handling this type of auth logic and connecting to a redux store.

One of the (several) pitfalls here is that even if you could login a user to your 'protected' route, if they were to logout while in 'protected' they would never get redirected to 'login' because it wouldn't trigger the onEnter.

An alternative approach is to use Higher Order Components, see Dan Abramov's post about using them over mixins, and I find them really useful in this context as well. There have been a few gists/example repos out there of how to use them, but I've recently created a library redux-auth-wrapper specifically for this purpose. Its pretty new but I think it might be useful and avoids some dangers when using HOC's incorrectly for auth which can result in infinite-loop-redirects.

The idea of using a HOC is that it is a function that when applied to a components extends its functionality in some way. Users of redux are most likely familiar with connect to enhance Components with the subscription for the store.

In this case, the Component you write is unaware of being protected by authentication/authorization and when applied the HOC function, a new component with the given checks is returned. Should those pass, the wrapped component is returned, else the user is redirected to a place to login (or somewhere else if its an authorization issue). The HOC makes use of componentWillMount and componentWillReceiveProps lifecycle methods to determine wether or not the user is allowed to see the given component. This allows support for redirecting out of components on authentication change even if the route does not.

I'd also check out examples of a similar strategy here: https://github.com/joshgeller/react-redux-jwt-auth-example.

And here is an example that uses the onEnter for auth with some store trickery, but I believe it will not handle the edge case described above: https://github.com/CrocoDillon/universal-react-redux-boilerplate/blob/master/src/routes.jsx.

Sign up to request clarification or add additional context in comments.

4 Comments

I have similar issue as Andrew, but I'm using HOC. My issue is that the user can't login, because it is always checking the current state before the response comes back from the server - and this means the user can't login. Is there a way to throttle the check in the redux store?
@Abdi yeah I've come across a similar issue here: github.com/mjrussell/redux-auth-wrapper/issues/30. I think the solution is to just add a flag to your redux store (isUserFetched) or something like it and if true - instead of performing the redirection, show an alternate page in the HOC instead of the wrapped component. (like a loading page). I want to add this to my library soon, just haven't yet had time
I have actually managed to fix the issue without resorting to a in the middle page. I used redux- thunk - which makes the action wait to resolve and then I update the state and then redirect. Hope this makes sense, but if you have a similar issue definitely look into redux-thunk. I also found this repo very helpful since it was doing what I wanted to implement HOC with authentication
@Adbi could you please show an example about the redux-thunk implementation you used to solve this issue? My problem is if the user refresh the page i would like to check to token before rendering the protected view

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.