2

I am trying to setup a new front-end project using react, react-router and redux and I'm stumbling on setting up a login workflow that works well and with many pages.

Here is the logic that I want to have:

  1. Have a variable in the redux store that says if I'm logged in or not. To simplify let's say that we have logged: true/false.
  2. When logged is set to true from the login page, redirect to the page we were redirected from, or redirect to / if not defined. The previous location is stored in nextPathname.
  3. When logged is set to false in a component that requires auth, redirect to /.

My main problem with this workflow is that I want to dispatch an action (set the logged value) and then do a redirection.

Here are a few alternatives that I have explored:

  1. Check if logged==true in my login component's componentWillReceiveProps and redirect if it's the case. This works well for the login workflow but if I have to implement such a logic for the logout component, I have to do it for each component that requires auth. (Mixins don't work thanks to ES6 react components...).
  2. Handle the redirections in a middleware: when the action is about login, run the action and then redirect. However I don't know if this is a best practice or not.

So my question is: how do I make the auth work without too much overhead on all pages that are restricted?

A bit of code:

app.js:

function requireAuth(nextState, replace) {
    if(store.getState().Login.logged === false) {
        replace({
            pathname: "/login",
            state: { nextPathname: nextState.location.pathname }
        });
    }
}
const history = syncHistoryWithStore(browserHistory, store);
ReactDOM.render(
    <Provider store={store}>
        <Router history={history}>
            <Route path="/" component={Archives} onEnter={requireAuth}></Route>
            <Route path="/login" component={LoginComponent}></Route>
        </Router>
    </Provider>,
    document.getElementById("app")
);

The LoginComponent:

class LoginComponent extends React.Component<LoginProps, any> {
    componentWillReceiveProps(newProps) {
        if(newProps.logged) {
            let nextPath = "/";
            const {location, history} = newProps;
            if (location.state && location.state.nextPathname) {
                nextPath = location.state.nextPathname;
            }
            history.pushState({}, nextPath);
        }
    }
    render() {
       return <div>This is a login form</div>
    }
}

1 Answer 1

5

The way you'll want to approach this, I believe, is by using a 'RequireAuth' higher order component to wrap your components that the user needs to be authenticated to access. Here's an example of such, just pay attention to the auth components in the client folder: https://github.com/joshuaslate/mern-starter

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

4 Comments

Wow that looks simple and easy! I'll experiment with this!
Please let me know if you stumble across any ways to improve the auth flow I've got going there, as this is what I've been using to start my apps. Good luck!
Works like charm! Thanks! My only suggestion would be to add a bit of documentation in the readme...
Definitely agree that a HOC is the right approach for this. I've got a small HOC library that has pretty similar logic (componentWillMount/willRecieveProps). Its got a few more config options for handling various scenarios (such as displaying a LoadingComponent while authenticating). github.com/mjrussell/redux-auth-wrapper

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.