48
votes

Does anyone have experience creating an authentication mechanism with the new router in pre4?

Here are some of my thoughts so far:

  • In order to completely separate the view (Ember app) from the server (Rails app) I want to use token authentication. I will likely use Devise on the Rails server.
  • I need something like a before_filter equivalent in the Ember app where I can check if there is a current user and if that user has an authentication token set.
  • The Rails server will return the current auth token on every call. If it returns a null auth token the Ember app should detect this and transition to the unauthenticated state, redirecting to the login view.

I suspect I should be using an Ember state machine for this but I'm not sure how to proceed. Anyone tackled this problem yet?

5

5 Answers

51
votes

UPDATE: Like @DustMason says in his answer, check out the awesome embercasts for authentication best-practices.

In order to completely separate the view (Ember app) from the server (Rails app) I want to use token authentication. I will likely use Devise on the Rails server.

Makes sense.

I need something like a before_filter equivalent in the Ember app where I can check if there is a current user and if that user has an authentication token set.

You can add an enter hook on routes, this is roughly equivalent to a before_filter. But not sure that's the best place to check for an auth-token.

The Rails server will return the current auth token on every call.

Makes sense. We use cookie-auth and fetch current user profile by calling /api/me but either should work.

If it returns a null auth token the Ember app should detect this and transition to the unauthenticated state, redirecting to the login view.

Thing about this approach is that (unlike rails) it's not easy to "protect" access to a particular ember routes. And no matter what a user can always pop open JS console and enter whatever state they want. So instead of thinking "user can only get into this state if authenticated" consider "what if unauthenticated user somehow navigates to this route"

I suspect I should be using an Ember state machine for this but I'm not sure how to proceed. Anyone tackled this problem yet?

Our auth needs are pretty simple so we've not found the need for a state machine. Instead we have an isAuthenticated property on ApplicationController. We use this property in application.hbs to replace the main view with a login form when a user is not authenticated.

{{if isAuthenticated}}
  {{render "topnav"}}
  {{outlet}}
{{else}}
  {{render "login"}}
{{/if}}

From ApplicationRoute, we fetch user profile:

App.ApplicationRoute = Ember.Route.extend({
  model: function() {
    var profiles;
    profiles = App.Profile.find({ alias: 'me' });
    profiles.on("didLoad", function() {
      return profiles.resolve(profiles.get("firstObject"));
    });
    return profiles;
  }
});

Then our ApplicationController computes it's isAuthenticated property based on the profile that was returned.

19
votes

I would suggest using ember-auth for that. It implements all the needed functionality and works very well in my opinion.

Also there is a demo and tutorial with Devise on Rails by the same author.

I also have implemented a basic Ember application based on Ember-auth with Devise token authentication and example Oauth for Google and LinkedIn that can be found here and is live here: https://starter-app.herokuapp.com

12
votes

I recently changed from a bespoke auth system to using ember-simple-auth and found it very easy to integrate with my app. It fulfills all of the OPs requirements and also has built in support for refresh tokens.

They have a really nice API and a great set of examples. Anyone interested in token based auth should check it out.

4
votes

The newly released Ember async router makes setting up a nice auth flow easier in my opinion! Check out the two-part series on http://www.embercasts.com/ for a good example

3
votes

Josep's example app is really nice. I made a copy of his repo to show how to do it with ActiveRecord instead of mongoid, and also enable the Devise confirmable module. You can find it here. This repo was reconstructed from scratch, rather than forked, as I wanted to force myself to go through all of the steps to get it working. I'll update this answer if I add a fork with the necessary changes to get it to work.