Ember authentication best practices? - ember.js

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?

UPDATE: Like #DustMason says in his answer, check out the awesome embercasts for authentication best-practices.
Client Side Authentication Part I
Client Side Authentication Part II
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.

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

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.

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

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.

Related

JWT Authentication with Rails and Ember JS

What is the right way to proceed the logout action of the User when using JWT, Rails API and a JS front-end framework, for example Ember JS ? What I'm actually doing is:
use Rails 5.2 as API
use Ember JS 3.3 as front-end
use Ember Simple Auth as OAuth add-on
example app, its master branch, works as needed
example app, its without login branch fails to logout the User
check the presence and pass in a token in every request between Rails API and Ember JS apps.
The questions I have are:
Should I keep a token value in the backend model (User, for example) ?
I need it to make another request in the background on the backend side.
Should I set the token value to nil when the User logs out in the backend ?
What am I doing wrong with ESA as for logout action ?
Actually the token value is kept in a cookie on the client side (see https://github.com/simplabs/ember-simple-auth for more details). I followed their guides and the dummy app they provide.
I also had a discussion on Ember JS Forum and tried to follow some tips and advises, still no success.
Thank you.
This answer applies to Ember 1.13 through at least 3.x.
Authentication comes in so many flavors that I think the right way to do it is whatever is an easy-to-understand fit with the back end.
Since your JWT is in a cookie, let's think of that cookie as the source of truth. Rather than doing something complicated to parse the cookie in a model hook, you could define a Service that has functions to grab the cookie, parse it, and either save the results to values on the service or return the values you need.
This gets you a few benefits. You can get the values from anywhere in your app, including adapters, and all the logic for auth lives in once place. On the other hand, you would have to handle async behavior yourself (i.e. if a route depends on having login info, you will have to manage the order of operations between authentication and route transitions).
Ember Simple Auth is quite popular because of this issue. Although there aren't out of the box features for JWTs in cookies, if you have an app with different states based on logged-in behavior, it might be a good investment to learn it.
The user model is kind of a middle ground between a hand-rolled service and Ember Simple Auth, since you can get the user model and rely on it throughout your app, plus get a little help with async. Just be careful not to scatter your auth code across your whole app.
Lastly, to trigger logout, I would create a function that destroys the cookie by setting the max age/expiration like this. If you are handling auth on a service, this means you could use Router Service and then transitionTo a login page. If you are using Ember Simple Auth, that functionality can go in the invalidate hook of your custom authenticator. Example:
invalidate() {
this._super()
document.cookie = "some_token_name=; expires=Thu, 18 Dec 2013 12:00:00 UTC; path=/"
return Promise.resolve();
}
Lastly, for passing the token to authenticate requests, if you are using Ember Data, this can be done easily in the adapter's headers method.

How can I set up an Ember Simple Auth session in dev with data from Mirage?

I want to configure the Ember Simple Auth session to be authenticated for a user generated by Ember CLI Mirage on startup. During testing I can use the Ember Simple Auth authenticateSession() helper, but as far as I can tell, this isn't available during development. Is there a way to update the session before the app boots?
If you're just looking to change the behavior of Ember Simple Auth on the client and in a situation where your Ember app never makes an XHR request, Mirage won't be able to help you out here. You could fake the login request (which may set some user data), but if you want to change the logged-in user without going through xhr authentication, you'll need to use environment-based config to change how Simple Auth behaves.
(I know this is not a complete answer to your question, I just wanted to point out that Mirage only knows how to handle XHR requests, and it sounds like your problem involves client-side state.)

Ember Simple Auth when all pages requires authorization

I have website that requires authorization on all its pages. To achieve that there is server that response based on cookie. If there is cookie send ember app, login site otherwise. This allows to facebook like behavior. I am using ember-simple-auth addon to help with authorization.
Since user is never inside app without being successfully authorized, one should be able to save ember-data record object into session. This works nice for one tab but breaks horrible with multiple tabs. Is there way how to have ember-data objects in session and yet support multiple browser tabs?
Edit:
I maybe found workaround, save index into session and use peekRecord in computed property.

Authenticate Facebook users in Cakephp 3x

I have used PHP SDK-4 for Facebook login in CakePHP 3 (beta version) which works fine.Now, I'm in need to fetch user data based on FB login and authenticate users. Am trying with Cake's Auth component. Initially, while trying to Auth users,
$this->Auth->setUser($user)
Got Error: Session was already started as we require session_start() for Facebook login. 1- Tried with enter link description here, and sessions [session_write_close()] etc..still it did not work. Could I get some shot on best way to authenticate users with Facebook login in site?
CakePHPs sessions are lazy started, that is, they are being started once your try to access the session in some way, and in case the session was started manually in beforehand, you'll receive that error, see Session::start().
You can easily workaround this by manually starting the session via CakePHP. The session object is available in the current request, so for example in your controller before using the SDK you could simply do something like
$this->request->session()->start();
and then the Facebook SDK should be able to pick it up.
As burzum already mentioned in the comments, the authentication should better be wrapped up in an authentication handler.
I would suggest having a look at HybridAuth, there's also a CakePHP plugin for seamless integration into CakePHPs auth mechanism, this might give you some ideas for a custom implemenation in case you need to use the v4 SDK, which isn't yet supported by HybridAuth.

Register & login to django backend from iphone app and mobile browser

We are building a Django backend with an iphone app and also would like to allow login through web/mobile browsers.
The requirement is to be able to register and logon from the website/mobile browser and also through the iphone app. I have also integrated django-registration for registration, login, logout etc.
What would be the preferred approach so that register, login, logout can be doen through the iphone app as well as mobile browser?
The most discussed approach seem to be the following:
Use tastypie for a RESTful API(or any other framework for REST) ( In
this case, I assume that means create an api for register and login)
For iphone, use RESTKIT to call and authenticate the backend to
perform login, registration etc.
Security and ability to only see relevant data for the user is important in our case as the data is highly sensitive.
Any advice is much appreciated and surely will help others too.
Thanks in advance.
Neo
If you have already integrated django-registration on your website, then you don't necessarily need to add tastypie just for login,logout etc.
Check out the documentation for django-registration at https://django-registration.readthedocs.org/en/latest/quickstart.html#setting-up-urls. If you follow the steps for the default setup, that should provide you with URLs for login, logout etc. If the section on "Required Templates" doesn't make sense to you here, read more about django at http://www.djangobook.com/en/2.0/chapter04.html
Once you have these URLs, you can simply make use of the AFNetworking library on iOS to create HTTP requests to login / logout etc.
Typically, a django view for registration will serve GET and POST requests differently. If you make a GET request, it will format the registration form and display the HTML page. If you make a POST request, it will first extract the information required for registration from the request and create a new user. This will happen automatically for the web.
Making use of AFNetworking, you can create a view that shows the form locally and then makes the corresponding POST request once the user wants to register. The same procedure applies for login.