Meteor Roles and Flow Router Route Authentication Problems

If you ever played with Meteor, you most likely started adding routes so you have various pages in your project.

If you started getting more serious with your project you added user authentication and then roles to restrict access to certain features to various types of users.

This is quite a common scenario and two of the most used and great packages for these two features are Alanning Meteor Roles and Kadira Flow Router.

It would then make sense you ran into an issue when trying to allow a user onto a specific route, only if that router pertains to a specific role.
This is of course more of a convenience feature, rather than real security, as it all happens on the client. It is quite good to have nonetheless.

The issue in question being that Roles.userIsInRole(Meteor.userId(), ['admin']) would return false even if the user was in that role when the page was refreshed.

If you read through all the docs, issues, stack overflows you will find out that want happens is that the Roles package is dependant of the Roles.subscription to be ready before it can check the roles. It makes sense. It also make sense that the subscription would not be ready as soon as your routes.js runs.

Solution

What can we do? Well, fortunately Flow Router has the possibility of doing deferred initialisation, pending your cue to get going.
In one of your clients JS files, top level you could add something like this:

FlowRouter.wait();

Tracker.autorun(() => {
  // wait on roles to intialise so we can check is use is in proper role
  if (Roles.subscription.ready() && !FlowRouter._initialized) {
    FlowRouter.initialize()
  }
});

Just be aware that if FlowRouter waits, so does your page loading and your users. Fortunately the Roles subscription is very small and fast.

After that, in your routes’s triggers you can just check id the user is in a specific role.

/* admin stuff *** very hush hush, much secret */
let adminRoutes = FlowRouter.group({
  prefix: '/admin',
  name: 'admin-group',
  triggersEnter: [(context, redirect) => {
    if (!Roles.userIsInRole(Meteor.userId(), ['admin'])) {
      redirect('/dont-go-there');
    }
  }],
});

I hope this helps 😉

Category: blog

Tags: ,

- July 7, 2016