Authentication using Tracker

When a user is not logged into my Meteor app, I want to show a login page. As I’ve had some problems using onRun and onBeforeAction hooks of iron:router>=1.0.0, I’m now thinking about using Meteor’s Tracker.

This is the code I’ve written:

Meteor.startup ->
  Tracker.autorun ->
    loggedIn = Meteor.user() or Meteor.loggingIn()

    return  if loggedIn

    Tracker.nonreactive ->
      currentRoute = Router.current()?.route?.getName()

      if currentRoute isnt 'login'
        alert 'Show Login'
        Router.go '/login'

It works great when a user is logged in, and then logs out - he will be redirected to the login page. However, when I access the app for the first time and the user is not logged in, I get the alert but iron:router doesn’t redirect the user the login page (but sometimes changes the url to /login). What’s wrong with my approach?

Wow, thats an err… interesting way to do it! What was the issue with Iron Router’s onBeforeAction out of interest? That’s certainly the more “correct” way to handle this sort of thing.

EDIT: Something like:

Router.onBeforeAction(function() {
  if (!Meteor.user()) {
    if (Meteor.loggingIn()) {
      this.render(this.loadingTemplate);
    } else {
      this.render('login');
    }
  } else {
    this.next();
  }
});

@fvg, I cannot help you on your specific case because I am not cs-literate. However, to react to @Siyfion’s answer, I wanted to point out that using autorun to track user login or route change is legitimate and, in my opinion, often preferable to Iron Router’s hooks.

While I agree that this strategy would work, why would it ever be preferable to tracking a route-change within the router code itself? If someone gave me this code to work on, I wouldn’t think to look in the Meteor.startup(...) code for route-change event handling; I’d look in the routing code. Conversely, if your application starts crashing on startup, I wouldn’t expect to have to look in the routing logic to figure out what’s causing it. For readability, understandability and debugging purposes alone, I’d keep as much of the routing logic in the router.

  1. In many modern applications, a route does not represent an application state. So there is no such thing as a “routing logic”. A route is just one data source, which, together with other data sources, will bring to an application state. Tracking these states in the routing code is not the right thing to do, in my opinion.

  2. Even if, in your application, a route represents an application state, I would advise any Meteor beginner to:

  • stay away from Iron Router (try meteorhacks:flow-router instead), or at least
  • stay away for Iron Router hooks (you’ll just get headache).

I’m sorry but I completely disagree on both points.

  1. We are talking about a function here that changes the current route based on whether they are logged-in or not. To me, something that controls routing-logic belongs in the router. That’s exactly why the Router has these hooks in the first place.

  2. Stay away from Iron Router? Seriously? While I appreciate that flow-router is considered a “cleaner” router and perhaps one to use in future (definitely one to keep an eye on!), I would certainly not be recommending that beginners start with flow-router; the almost un-documented, example-less and hardly used & tested router.

EDIT: Oh and even flow-router's minimal documentation does go give an example of precisely this use-case: https://github.com/meteorhacks/flow-router/#middlewares (ie. a middleware / router-hook for redirection)

Sorry, I didn’t convert the code into JS because of the existential operator, which is clearer in coffeescript.

The problems with iron:router hooks appeared when I made the switch from 0.9.4 to > 1.0.0 versions. I’m using zimme:iron-router-auth and always hooked it into the router using a onBeforeAction. This doesn’t work anymore, I have to use onRun, which works. Now there are situations where I don’t get redirected after logout.

I find that iron:router is so not predictable, so I’ll switch to flow-router anyway, once there is something like martino:iron-router-i18n for it. Just like in the code I posted, why doesn’t iron:router just go to the login page? There might be a good reason but it’s just hard to understand. flow-router seems really light, is easy to understand and implement.