48

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?

Sean Rucker
  • 1,066
  • 2
  • 11
  • 20

5 Answers5

51

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.

Mike Grassotti
  • 19,040
  • 3
  • 59
  • 57
  • 2
    I marked accepted as this got me on the right track. Can you elaborate on the comment you made: "Makes sense. We use cookie-auth and fetch current user profile by calling /api/me but either should work." What is cookie-auth? Do you still use token authentication and store the token in a cookie after logging in? – Sean Rucker Feb 01 '13 at 23:04
  • Sure - guess "cookie-auth" isn't really a thing. What I mean is that we are using rails cookie-store for sessions. Our API expects the user to have a valid session, and returns current_user when /api/me is requested. – Mike Grassotti Feb 04 '13 at 03:24
  • 1
    Quick note, but the "`enter`" hook you mention is now deprecated and instead replaced with "activate" (and corresponding "`deactivate`") – Kevin Ansfield Feb 16 '13 at 17:41
  • 2
    What if the ember app thinks it's authenticated but it's not (e.g. server has expired the session key)? How does it detect this state and redirect back to the login form? – adam smith Mar 14 '13 at 23:57
  • 2
    @adamsmith that's a good question. Not an issue for us, but i can see how it might be. Ideally your API will return an `HTTP 403` the next time an API call is made. Then customize your ember-data adapter to handle this case and modify `isAuthenticated` property of your application controller. – Mike Grassotti Mar 25 '13 at 16:00
  • I would advise against returning the current auth token back from the server with every request. Why not have the server check whether or not the auth is good and send back a 401 Unauthenticated response if not? You can also attach a message from the server with that 401 response if needed. Then ember can catch that and redirect – Jordan Sitkin Jun 30 '13 at 20:33
  • @DustMason agreed, now that i think about it returning current auth with every request not advisable. That said ember has evolved quite a bit since my original answer, the "router facelift" makes authentication much more straightforward. Anyone looking to do this now should have a look at the latest embercast: http://www.embercasts.com/episodes/client-side-authentication-part-2 – Mike Grassotti Jul 01 '13 at 05:57
  • How can you have `isAuthenticated` inside your Ember app? This is all contained within the browser, meaning it's much easier for a user to mess with this. Even with intermediate javascript experience you'd be able to change that to `true`. Running authentication logic in the client-side should not even be debated, it's a no-go – Marco Prins Jun 30 '15 at 13:18
  • @MarcoPrins for sure you are correct, nobody is recommending that authentication state be managed on the client side. That's done at the API layer. Setting `isAuthenticated=true` will allow a user to trick client app but API requests will fail. – Mike Grassotti Jun 30 '15 at 17:16
19

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

joscas
  • 7,474
  • 5
  • 39
  • 59
12

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.

Martin Stannard
  • 811
  • 8
  • 22
4

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

Jordan Sitkin
  • 2,303
  • 3
  • 26
  • 35
3

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.

jhosteny
  • 554
  • 3
  • 8