Announcing Torii 0.6.0

Wow! This takes me back! Please check the date this post was authored, as it may no longer be relevant in a modern context.

Torii is an authentication library for Ember.js. Much of the motivation behind Torii is introduced in this blog post from last summer. Unlike the popular Devise gem for Rails, Torii attempts to do little by default. Instead, it focuses on providing useful primitives and a conventional authentication lifecycle.

Over the past year Torii has grown popular. We’ve started to learn what patterns work across many apps and which ones should be avoided.

Torii 0.6.0, with amazing help from many contributors, formalizes several of these best practices into features. These include:

  • OAuth 2.0 state support, securing applications from CSRF attack
  • Exposing torii and the opt-in session support as Ember services
  • Adding a test helper for stubbing session state
  • Introducing support for flagging routes as “authenticated” in Ember’s router DSL

Lastly we’ve worked quite hard to ensure Torii 0.6.0 is still compatible with Ember.js 1.12, and supports all versions up to the current 2.1 betas without raising deprecations. This makes Torii 0.6.x a good version to use when migrating to Ember 2.x.

In Torii 0.7.0 we’re aiming to ship two big changes: Porting Torii into a traditional Ember-CLI addon (this will likely mean the removal of Torii’s “globals” mode support), and an iframe flow the provides an alternative to the popups we use for OAuth today.

But let’s take a look at these 0.6.0 features in detail.

OAuth 2.0 “state”

OAuth 2.0 recommends “state” to protect against CSRF attacks. Support for clients is optional, and the impact of CSRF varies from workflow to workflow in OAuth2. Some support from the provider is required, however many providers already support state.

The delightful @alisdair added transparent support for OAuth2 state to Torii in 0.6.0. This grants existing users improved protection against CSRF attacks on their authentication system. Current users of Torii only need to upgrade to 0.6.0, everything else is done by the library. See #217 for more details.

Using Ember Services

Torii is fairly “mature”, and by that I mean it predates some APIs we take for granted in Ember today. One of these is Ember’s excellent service and lazy dependency injection system. Before 0.6.0, accessing Torii or the opt-in session service from a component was clumsy at best.

In 0.6.0, simply use Ember.inject.service:

// app/components/open-facebook-auth.js
import Ember from 'ember';

export default Ember.Component.extend({
  torii: Ember.inject.service('torii'),
  click() {
    this.get('torii').open('facebook-oauth2').then((result) => {
      this.sendAction('didOpenAuth', result);
    });
  }
});

To opt-in to Torii’s session management, you must configure a service name via sessionServiceName in config/environment.js. That configured name, say “session”, is also available as a service name.

Please note that this change introduces a small breaking change in Torii: The torii:main factory has been renamed service:torii, and the configured session service name will also be prefixed by service:, for example service:session. Both services are still injected on routes and controllers, as in previous versions of Torii.

Thanks to @pzuraq for implementing this change.

New Testing Helper

Users of Torii’s opt-in session management need a way to stub authenticated states for testing. We still recommend mocking AJAX responses for testing sign-in and session restoration, however for testing unrelated features this is a slow and cumbersome method to mock signed-in state.

0.6.0 introduces test helpers for Torii, specifically stubValidSession. Thanks to our friend @jagthedrummer for implementing this.

Authenticated Route DSL

Ember’s nested routes present an ideal platform for flagging part of an app as requiring authentication. Usually this is done with a mixin, and toggling a flag on the route class. We’ve found that a difficult to use API. When first getting into a codebase, this important detail is buried.

Torii 0.6.0 features a powerful new way to require authentication for a route. For example, given a codebase opted-in to Torii’s session management:

// app/router.js
import Ember from 'ember';

Router.map(function(){
  this.route('about');
  this.route('sign-in');
  this.authenticatedRoute('dashboard', {}, function(){
    this.route('settings');
  });
});

When any route in this application is visited, checkLogin will be called on the application route with a default behavior of silently checking for a session named application. Attempts to access the dashboard without a session will trigger an accessDenied action on the route. Implementing accessDenied with an appropriate redirect is left to the developer.

Read more about this API in the Torii readme, and thanks to @tarasm for completing a tricky implementation process!