1 week ago

Testing with Ember Simple Auth and Ember CLI

The last blog post showed how to use Ember Simple Auth with Ember CLI to implement session handling and authentication. This post shows how to test that code.

The testing package

First of all install the new ember-cli-simple-auth-testing package:

npm install --save-dev ember-cli-simple-auth-testing

This package adds test helpers to the application (unless it’s running with the production environment) that make it easy to authenticate and invalidate the session in tests without having to stub server responses etc. To make these helpers available to all tests, import them in tests/helpers/start-app.js:

tests/helpers/start-app.js:
…
import 'simple-auth-testing/test-helpers';

export default function startApp(attrs) {
…

Configuring the test environment

The next step is to configure the test environment. As the tests should be isolated and leave no traces of any kind so that subsequent tests don’t have implicit dependencies on the ones that have run earlier, Ember Simple Auth’s default localStorage store cannot be used as that would leave data in the localStorage. Instead configure the ephemeral store to be used in the test environment:

// config/environment.js
if (environment === 'test') {
  ENV['simple-auth'] = {
    store: 'simple-auth-session-store:ephemeral'
  }
}

The ephemeral store stores data in memory and thus will be completely fresh for every test so that tests cannot influence each other.

Adding the Tests

Now everything is set up and a test can be added. To e.g. test that a certain route can only be accessed when the session is authenticated, add tests like these (notice the use of the test helpers authenticateSession and invalidateSession):

test('a protected route is accessible when the session is authenticated', function() {
  expect(1);
  authenticateSession();
  visit('/protected');

  andThen(function() {
    equal(currentRouteName(), 'protected');
  });
});

test('a protected route is not accessible when the session is not authenticated', function() {
  expect(1);
  invalidateSession();
  visit('/protected');

  andThen(function() {
    notEqual(currentRouteName(), 'protected');
  });
});

This is how easy it is to test session handling and authentication with Ember Simple Auth and Ember CLI. The full example project can be found on github

1 week ago

Talk on using Ember Simple Auth with Ember CLI I gave at the July Ember.js Munich Meetup

1 month ago

Using Ember Simple Auth with ember-cli

With the latest release of Ember Simple Auth, using the library with ember-cli has become much simpler. As ember-cli in general is still pretty new to many people though, this post describes how to setup a project using Ember Simple Auth with ember-cli.

Setting up the basic project

First of all you need to install PhantomJS, bower and of course ember-cli:

npm install -g phantomjs
npm install -g bower
npm install -g ember-cli

Then use ember-cli to create the new project:

ember new my-auth-app

At this point the basic project is set up and ready to run:

cd my-auth-app
ember server

Installing Ember Simple Auth

Installing Ember Simple Auth in an ember-cli project is really easy now. All you have to do is install the ember-cli addon from npm:

npm install --save-dev ember-cli-simple-auth

This will install Ember Simple Auth’s AMD distribution into the project, register the initializer so Ember Simple Auth automatically sets itself up and add itself as a dependency to the project’s package.json.

You can add a login route and login/logout links to verify it all actually works:

// app/router.js
…
Router.map(function() {
  this.route('login');
});
…
// app/templates/application.hbs
…
{{#if session.isAuthenticated}}
  <a {{ action 'invalidateSession' }}>Logout</a>
{{else}}
  {{#link-to 'login'}}Login{{/link-to}}
{{/if}}
…

Also implement the ApplicationRouteMixin in the project’s application route:

// app/routes/application.js
import Ember from 'ember';
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';

export default Ember.Route.extend(ApplicationRouteMixin);

Setting up authentication

To actually give the user the option to login, we need to add an authentication package for Ember Simple Auth. Let’s assume you have an OAuth 2.0 compatible server running at http://localhost:3000. To use that, install the OAuth 2.0 extension library which again is as easy as installing the package from npm:

npm install --save-dev ember-cli-simple-auth-oauth2

Like the ember-cli-simple-auth package this will setup itself so that nothing else has to be done in order to use the OAuth 2.0 functionality.

The OAuth 2.0 authentication mechanism needs a login form, so let’s create that:

// app/templates/login.hbs
<form {{action 'authenticate' on='submit'}}>
  <label for="identification">Login</label>
  {{input id='identification' placeholder='Enter Login' value=identification}}
  <label for="password">Password</label>
  {{input id='password' placeholder='Enter Password' type='password' value=password}}
  <button type="submit">Login</button>
</form>

Then implement the LoginControllerMixin in the login controller and make that use the OAuth 2.0 authenticator to perform the actual authentication:

// app/controllers/login.js
import Ember from 'ember';
import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';

export default Ember.Controller.extend(LoginControllerMixin, {
  authenticator: 'simple-auth-authenticator:oauth2-password-grant'
});

As the OAuth 2.0 authenticator would by default use the same domain and port to send the authentication requests to that the Ember.js is loaded from you need to configure it to use http://localhost:3000 instead:

// config/environment.js
if (environment === 'development') {
  …
  ENV['simple-auth-oauth2'] = {
    serverTokenEndpoint: 'http://localhost:3000/token'
  }
  …

As ember-cli adds all configuration to the global <app-name>ENV variable (e.g. in this case MyAuthAppENV) which Ember Simple Auth cannot use as it doesn’t know it’s name, you need to copy that to window.ENV so Ember Simple Auth can use it:

// app/initializers/simple-auth-config.js
export default {
  name:       'simple-auth-config',
  before:     'simple-auth',
  initialize: function() {
    window.ENV = MyAuthAppENV;
  }
};

You also need to make sure that your server allows cross origin requests by enabling CORS (e.g. with rack-cors if you’re using a rack based server).

Conclusion

This is how you set up an ember-cli project with Ember Simple Auth. For further documentation and examples see the github repository and the API docs for Ember Simple Auth and the OAuth 2.0 extension library.

1 month ago

Ember Simple Auth 0.6.0

Ember Simple Auth 0.6.0 introduced some significant improvements that make it a lot easier to use the library with Ember CLI as that’s the new de facto standard for building Ember applications.

No more initializers

First of all the requirement to define an initializer to set up the library has been dropped. With the recently introduced Ember CLI Addons system (see Robert Jackson’s great introduction), Ember Simple Auth can now be installed via npm and will register its initializer automatically:

npm install --save-dev ember-cli-simple-auth

Better Documentation

The documentation has been rewritten to focus on using the library with ES6 modules, e.g.:

// app/routes/application.js
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';

export default Ember.Route.extend(ApplicationRouteMixin);

Using the browserified version that exports the SimpleAuth global (which is no longer attached to the Ember global) is not really deprecated but I wouldn’t encourage anybody to using that in real projects as Ember CLI is clearly so much better.

So go on building great projects with Ember CLI and Ember Simple Auth and please report any bugs you encounter in the process!

3 months ago

Ember.SimpleAuth needs a logo!

Every good open source project needs a nice and shiny logo these days. It would be great if Ember.SimpleAuth had one as well. As I’m not really an expert in these things it would be great if some of the more artistic advanced contributors/followers could contribute something!

3 months ago

Ember.SimpleAuth 0.3.0

Ember.SimpleAuth 0.3.0 was just released. The main change in this release is the split of Ember.SimpleAuth into one core library and a set of extension libraries. These extension libraries include everything that’s not mandatorily required for Ember.SimpleAuth like authenticators, stores etc. so that every application would only have to load whatever it needs. These extension libraries are:

  • ember-simple-auth-oauth2: includes the OAuth 2.0 authenticator and authorizer which are just one option out of many and probably not needed in many projects (e.g. when using a custom authenticator)
  • ember-simple-auth-devise: new authenticator/authorizer package that is compatible with the Ruby gem devise.
  • ember-simple-auth-cookie-store: The cookie store which is probably only used in few projects.

There are hopefully more extension libraries to come as people start to provide more authenticators, authorizers and other components and now there’s a (more or less, pre 1.0) stable API for these libraries as well as a set of tasks to build and test them

Another bigger change in this release is that having an authorizer is now optional. As there are applications that are purely client side and don’t use a server backend expecting every application to use an authorizer was probably not so great in the first place. However, applications that do use an authorizer can simply configure one in Ember.SimpleAuth’s setup method and everything will behave as before:

Ember.Application.initializer({
  name: 'authentication',
  initialize: function(container, application) {
    Ember.SimpleAuth.setup(container, application, {
      authorizerFactory: 'authorizer:oauth2-bearer'
    });
  }
});

For more information about this release see the release notes at: https://github.com/simplabs/ember-simple-auth/releases/tag/0.3.0

3 months ago

Ember.SimpleAuth 0.2.1

Ember.SimpleAuth 0.2.1 was released with some minor improvements: https://github.com/simplabs/ember-simple-auth/releases/tag/0.2.1

4 months ago

Introduction to Ember.SimpleAuth - talk I gave at the Ember.js Munich Meetup in March 2014. The slides are available here.

4 months ago

Ember.SimpleAuth 0.2.0

Ember.SimpleAuth was released with a completely rebuilt build and testing infrastructure as well as some important bug fixes. Find the complete release notes on github.

6 months ago

Ember.SimpleAuth 0.1.0

Since Ember.SimpleAuth was released in October 2013, there were lots of issues reported, pull requests submitted and merged etc. Now all this feedback together with some fundamental design improvements results in the release of the 0.1.0 version of Ember.SimpleAuth. This is hopefully paving the way for a soon-to-be-released version 1.0.

What changed?

The most significant change is the extraction of everything specific to specific authentication/authorization mechanisms (e.g. the default OAuth 2.0 implementation) into strategy classes which significantly improves customizability and extensibility. Instead of having to override parts of the library, using e.g. a custom authentication method is now as simple as specifying the class in the respective controller:

App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin, {
  authenticator: App.CustomAuthenticator
});

This makes implementations cleaner and also helps defining the public API that Ember.SimpleAuth will settle on in the long term.

Other changes include the introduction of store strategies (Ember.SimpleAuth comes with a cookie store that is equivalent to the old store, a store that uses the browser’s localStorage API and which is the new default as well as an in-memory store which is mainly useful for testing) as well as error handling/token invalidation, added callback actions like sessionInvalidationSucceeded etc. See the README and the API docs for complete documentation.

Upgrading

Upgrading will be pretty straight forward in most cases. The main change that could bite you is probably the change in Ember.SimpleAuth.setup's signature. While it used to expect the container as well as the application instance, the container argument was dropped as it wasn’t actually needed. So in the initializer, change this:

Ember.Application.initializer({
  name: 'authentication',
  initialize: function(container, application) {
    Ember.SimpleAuth.setup(container, application);
  });
});

to this:

Ember.Application.initializer({
  name: 'authentication',
  initialize: function(container, application) {
    Ember.SimpleAuth.setup(application);
  });
});

Also, as the login and logout actions in ApplicationRouteMixin were renamed to authenticateSession and invalidateSession, in your templates change this:

{{#if session.isAuthenticated}}
  <a {{ action="logout" }}>Logout</a>
{{else}}
  <a {{ action="login" }}>Login</a>
{{/if}}

to this:

{{#if session.isAuthenticated}}
  <a {{ action="invalidateSession" }}>Logout</a>
{{else}}
  <a {{ action="authenticateSession" }}>Login</a>
{{/if}}

Also the LoginControllerMixin's login action was renamed to authenticate so in your login template change this:

<form {{action login on='submit'}}>

to this:

<form {{action authenticate on='submit'}}>

These are really the only changes needed if your application is using Ember.SimpleAuth’s default settings, the default OAuth 2.0 mechanism etc. For other scenarios, see the README, API docs and also the examples provided in the repository.

Outlook

I hope that this release can pave the way towards a stable API for Ember.SimpleAuth. It would also be great of course if many people came up with authenticator and authorizer implementations for all kinds of backends to prove the design of Ember.SimpleAuth’s strategy approach as well as to build a library of ready-to-use strategies for the most common setups.

9 months ago

Ember.SimpleAuth implements RFC 6749 (OAuth 2.0)

Update: Ember.SimpleAuth 0.1.0 has been released! The information in this is (partially) outdated.

With the release of Ember.SimpleAuth 0.0.4 the library is compliant with OAuth 2.0 - specifically it implements the "Resource Owner Password Credentials Grant Type" as defined in RFC 6749 (thanks adamlc for the suggestion). While this is only a minor change in terms of functionality and data flow, used headers etc. it makes everyone’s life a lot easier as instead of implementing your own server endpoints you can now utilize one of several OAuth 2.0 middlewares that already implement the spec.

With the OAuth 2.0 support also comes support for access token expiration and refresh tokens. Using expiring access tokens improves overall security as replay attacks are less likely while with refresh tokens Ember.SimpleAuth can automatically obtain new access tokens before they expire so that the user doesn’t recognize the token actually changes.

Other changes

Other smaller additions include support for external OAuth/OpenID providers and manipulation of the request used to obtain the access token. Also the API was simplified and the login and logout actions were moved to the ApplicationControllerMixin and the /logout route has been removed. The new API now looks like this:

Ember.Application.initializer({
  name: 'authentication',
  initialize: function(container, application) {
    Ember.SimpleAuth.setup(container, application);
  }
});
 
App.Router.map(function() {
  this.route('login');
  this.route('protected');
});
 
App.ApplicationRoute = Ember.Route.extend(Ember.SimpleAuth.ApplicationRouteMixin);
App.LoginController  = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin);

Future plans

Currently I’m working on adding API documentation within the source together with a means of generating some nice HTML out of that. I don’t currently see that there is much else missing in the library so I’d like to release a 1.0.0 version soon. Of course I’d like to make sure that Ember.SimpleAuth is actually being used and working so please submit bug reports, patches etc. or provide general feedback/ideas!

9 months ago

Ember.SimpleAuth

Update: Ember.SimpleAuth 0.1.0 has been released! The information in this is (partially) outdated.

After I wrote 2 blog posts on implementing token based authentication in Ember.js applications and got quite some feedback, good suggestions etc., I thought it would be nice to pack all these ideas in an Ember.js plugin so everybody could easily integrate that into their applications. Now I finally managed to release version 0.0.1 of that plugin: Ember.SimpleAuth.

Instead of providing a heavyweight out-of-the-box solution with predefined routes, controllers etc., Ember.SimpleAuth defines lightweight mixins that the application code implements. It also does not dictate anything with respect to application structure, routing etc. However, setting up Ember.SimpleAuth is very straight forward and it can be completely customized. The requirements on the server interface are minimal (see the README for more information on the server side).

Using Ember.SimpleAuth

Using Ember.SimpleAuth in an application only requires a few simple steps. First, it must be enabled which is best done in a custom initializer:

Ember.Application.initializer({
  name: 'authentication',
  initialize: function(container, application) {
    Ember.SimpleAuth.setup(application);
  }
});

The second step is to setup the routes for logging in and out:

App.Router.map(function() {
  this.route('login');
  this.route('logout');
});

Then, the generated controller and route must implement the mixins provided by Ember.SimpleAuth:

App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMixin);
App.LogoutRoute     = Ember.Route.extend(Ember.SimpleAuth.LogoutRouteMixin);

Of course the application also needs a template that renders the login form:

<form {{action login on='submit'}}>
  <label for="identification">Login</label>
  {{view Ember.TextField id='identification' valueBinding='identification' placeholder='Enter Login'}}
  <label for="password">Password</label>
  {{view Ember.TextField id='password' type='password' valueBinding='password' placeholder='Enter Password'}}
  <button type="submit">Login</button>
</form>

At this point, everything that’s necessary for users to log in and out is set up. Also, every AJAX request (unless it’s a cross domain request) that the application makes will send the authentication token that is obtained when the user logs in. To actually protect routes so that they are only accessible for authenticated users, simply implement the respective Ember.SimpleAuth mixin in the route classes:

App.ProtectedRoute = Ember.Route.extend(Ember.SimpleAuth.AuthenticatedRouteMixin);

More

There is more documentation as well as examples in the repository on github. Also the code base is quite small so I suggest to read through it to better understand what’s going on internally.

Patches, bug reports etc. are highly appreciated of course - get started by forking the project on github!

11 months ago

(better) Authentication in ember.js

Update:I released an Ember.js plugin that makes it very easy to implement an authentication system as described in this post: Ember.SimpleAuth.

When we started our first ember.js project in June 2013, one of the first things we implemented was authentication. Now, almost 2 months later, it has become clear that our initial approach was not really the best and had some shortcomings. So I implemented a better authentication (mostly based on the embercasts on authentication).

I’m using the latest (as of early August 2013) ember.js and handlebars releases in this example.

Update:I changed the section on actually using the token to use $.ajaxPrefilter instead of a custom ember-data adapter (thanks to Marc for the comment!)

The basics

The basic approach is still the same as in our initial implementation - we have a /session route in our Rails app that the client POSTs its credentials to and if those are valid gets back an authentication token together with an id that identifies the user’s account on the server side.

This data is stored in a "session" object on the client side (while technically there is no session in this stateless authentication mechanism, I still call it session in absence of an idea for a better name). The authentication token is then sent in a header with every request the client makes.

The client "session"

The "session" object on the client side is a plain Ember.Object that simply keeps the data that is received from the server on session creation. It also stores the authentication token and the user’s account ID in cookies so the user doesn’t have to login again after a page reload (As Ed points out in a comment on the old post it’s a security issue to store the authentication token in a cookie without the user’s permission - I think using a session cookie like I do should be ok as it’s deleted when the browser window is closed. Of course you could also use sth. like localStorage like Marc points out below). I’m creating this object in an initializer so I can be sure it exists (of course it might be empty) when the application starts.

When this has run I can always access the current "session" information as App.Session. Notice the .create() at the end of the initializer that creates an instance of the Ember.Object right away. When we need to check whether a user is authenticated we can simply check for presence of the authToken property. Of course we could add a isAuthenticated() method that could perform additional checks but we didn’t have the need for that yet.

This "session" object will also load the actual account record from the server if the authAccountId is set (this.set('authAccount', App.Account.find(authAccountId));. This allows us to e.g. use App.Session.authAccount.fullName in our templates to display the user’s name or similar data.)

To actually use the authToken when making server requests, we register an AJAX prefilter that adds the authentication token in a header as long as the request is sent to our domain:

The Rails server can then find the authenticated user by the token in the header:

Logging in

As described above, the login API is a simple /session route on the server side that accepts the user’s login and password and responds with either HTTP status 401 when the credentials are invalid or a session JSON when the authentication was successful. On the client side we have routes for creating and destroying the session:

The SessionNewController only needs one action login that sends the entered credentials and acts according to the server’s response - if the server responds successfully it reads the session data from the response and updates the App.Session object accordingly. It also checks whether there is an attempted transition that was intercepted due to missing authentication and retries that if it exists (This is the case where the user tries to access a certain page without having authenticated, is redirected to the login form, logs in and is redirected again to the initially requested page).

Notice that we do not handle the error case here. To have a better user experience you would probably want to define a .fail handler as well that display an error message.

The template is just a simple form (actual elements, classes etc. of course depend on your specific application:)

Logging out

Logging out is actually pretty simple as well. The client just sends a DELETE to the same /session route that makes the server reset the authentication token in the database so that the token on the client side is invalidated. The client also deletes the saved session information in App.Session so there’s no stale data.

As this action should be triggered as soon as the user enters the /#/session/destroy route, we have a simple route implementation that triggers the action upon route activation:

Authenticated routes

To easily enable authentication for any route in the application, I created an App.AuthenticatedRoute that extends Ember.Route and that all routes that need to enforce user authentication can extend again:

Notice that redirectToLogin sets the attemptedTransition of App.Session so that the user will be redirected to the initially requested page after successfulyl logging in.

This is better authentication with ember.js - enjoy!

1 year ago

"Mir persönlich wäre es am liebsten, wir machten mit unseren Mitstreitern in Deutschland ein eigenes Google auf", sagte Oliver Stock, Chefredakteur von Handelsblatt Online, zu Süddeutsche.de.

1 year ago

excellent 2.0.0

I just released excellent 2.0.0 which has some big improvements:

  • now supporting config file .excellent.yml in current working directory to configure which specs to run/ not to run with thresholds, patterns etc.
  • predefined globals will not be reported anymore ($!, $@, $&, $`, $’, $+, $1, $2.., $~, $=, $/, $, $„ $;, $., $, $_, $0, $*, $$, $?, $:, $”, $DEBUG, $FILENAME, $LOAD_PATH, $stdin, $stdout, $stderr, $VERBOSE, $-0, $-a, $-d, $-F, $-i, $-I, $-l, $-p, $-v)
  • enabled previously disable checks again: AbcMetricMethodCheck, ControlCouplingCheck, CyclomaticComplexityBlockCheck, CyclomaticComplexityMethodCheck, ForLoopCheck, FlogBlockCheck, FlogClassCheck, FlogMethodCheck
  • testing now uses Rspec 2
  • internal cleanups/ simplifications