React-Router Authentication?

I have two sections to my Meteor project:

  • Auth
  • App

When the user isn’t logged in, I want the user to be redirected to the auth. If the user is logged in, I want the user to be redirected to the app.

Sadly, making this work with react-router has been a bit of a pain.

How have you done react-router authentication in the past?

Anyone have any experience with this?

Your question seems really easy… which makes me think that I don’t understand it. I apologize if the following is non responsive.

import { browserHistory } from './react-router'
browserHistory.push('/app')

Hey mz103,

We recently switched over from Iron-Router to React-Router, and there are two patterns you may want to consider.

The first, which our company decided to go with, is to handle any authentication logic in your route component’s componentWillMount lifecycle method. In here, you can do as LawJolla suggests and import browserHistory to do something like:

import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import { isLoggedIn } from './route-authentication.js';

class HomePage extends Component {

  componentWillMount() {
    /**
    * Here the user will be redirected to the '/auth' route,
    * if they do not meet the isLoggedIn requirements. 
    */
    if (!isLoggedIn()) {
      browserHistory.push('/auth');
    }
  }

  render() {
    return (
      <div>
        Hello, World!
      </div>
    );
  }
}

To use the above method however, you have to have browserHistory enabled on react-router, as the default is hashHistory.

Alternatively, Route Components from react-router have an API for a onEnter method. Where you could do something like:

/**
* In authentication file...
*/
import Meteor from 'meteor/meteor';

export const isLoggedIn = (nextState, replace) => {
  /**
  * If there is no User currently logged in, redirect them 
  * to the '/auth' route.
  */
  if (Meteor.user === null) {
    replace({
      pathname: '/auth'
    });
  }
}

/**
* In Router file...
*/
import { isLoggedIn, otherEnterHookHere } from './authentication.js';

<Router>
  <Route path="/app" onEnter={isLoggedIn} />
  <Route path="/auth" onEnter={otherEnterHookHere} />
</Router>

These are very basic examples and you should definitely take a look at the API for react-router a bit more in-depth on their Github page. We went with the first pattern, simply because we were handling our data-loading through createContainer on the same component, and wanted to keep the Router logic clean. Let me know if this helps at all.

4 Likes

Thanks a ton anichale! Yes, it’s very helpful!

It looks like you did authentication at the route level, not the layout level.

To me, that means a lot of duplicated/redundant code. Why did you do it this way?

You should do authentification on the component level. You can do this in a “AppLayoutComponent” that is shared between different routes, no duplicated code.

By the way, I want to raise the question if it is a good practice to redirect not logged in users to a different route. If you do so, you’ll need to redirect the user back where he came from.

My usual approach is to just show the login form on any route that needs authentication, if the user is not logged in.

E.g. if he or she’s on /Auth and not logged in, simply show him a login form:

{ user ? <ComponentThatNeedsAuth /> : <LoginForm /> }

If user logs in, he or she will stay on /Auth, but will see

1 Like

So don’t use routes for login. Should we use routes for register and reset password? As far as I can tell, we kind of have to.

Also, if I use routes at the component level in a layout component like you said, I recieve the most vague tracker recompute error: React Exception from Tracker recompute function

yes, i think you need a route for register, because you want to link to that propably somewhere (“click here to register”)