[![Build Status](https://travis-ci.org/simplabs/ember-simple-auth.svg?branch=master)](https://travis-ci.org/simplabs/ember-simple-auth)

__[Ember Simple Auth API docs](http://ember-simple-auth.com/api/)__

__[![Slack Status](https://ember-community-slackin.herokuapp.com/badge.svg)](https://embercommunity.slack.com/messages/ember-simple-auth/)__

Ember Simple Auth __supports all Ember.js versions starting with 1.12.__

#  Ember Simple Auth

![Logo](http://ember-simple-auth.com/images/logo.png)

Ember Simple Auth is a __lightweight library for implementing authentication/
authorization with [Ember.js](http://emberjs.com) applications__. It has
minimal requirements with respect to application structure, routes etc. With
its pluggable strategies it __can support all kinds of authentication and
authorization mechanisms__.

# Table of Contents

**Basic Information**

* [What does it do?](#what-does-it-do)
* [How does it work?](#how-does-it-work)
* [Example App](#example-app)

**Usage**

* [Installation](#installation)
* [Walkthrough](#walkthrough)

**Core Feature Guides**

* [The Session Service](#the-session-service)
* [Authenticators](#authenticators)
  * [Customizing an Authenticator](#customizing-an-authenticator)
  * [Implementing a custom Authenticator](#implementing-a-custom-authenticator)
* [Authorizers](#authorizers)
  * [Customizing an Authorizer](#customizing-an-authorizer)
  * [Implementing a custom Authorizer](#implementing-a-custom-authorizer)
* [Session Stores](#session-stores)
  * [Store Types](#store-types)
  * [Implementing a Custom Store](#implementing-a-custom-store)
* [Testing](#testing)

**Other Guides**

* [Managing a current User](guides/managing-current-user.md)
* [GitHub authorization with torii](guides/auth-torii-with-github.md)

**Other Resources**

* [Upgrading from Pre-1.0 versions](https://simplabs.com/blog/2015/11/27/updating-to-ember-simple-auth-1.0.html)
* [API Documentation](http://ember-simple-auth.com/api/)

## What does it do?

* it __maintains a client side session__ and synchronizes its state across
  multiple tabs/windows of the application
* it __authenticates the session__ against the application's own server,
  external providers like Facebook etc.
* it __authorizes requests__ to backend servers
* it is __easily customizable and extensible__

## How does it work?

Ember Simple Auth consists of __4 main building blocks__ - the session, a
session store, authenticators and (optionally) authorizers.

The __session service is the main interface to the library__. It provides
__methods for authenticating and invalidating the session__ as well as for
setting and reading session data.

The __session store persists the session state__ so that it survives a page
reload. It also synchronizes the session state across multiple tabs or windows
of the application so that e.g. a logout in one tab or window also results in a
logout in all other tabs or windows of the application.

__Authenticators authenticate the session__. An application can leverage
multiple authenticators to support multiple ways of authentication such as
sending credentials to the application's own backend server, Facebook, github
etc.

__Authorizers__ use the data retrieved by an authenticator and stored in the
session to __generate authorization data that can be injected into outgoing
requests such as Ember Data requests__.

## Example App

__Ember Simple Auth comes with a
[dummy app](tests/dummy)
that implements a complete auth solution__ including authentication against
the application's own server as well as Facebook, authorization of Ember Data
requests and error handling. __Check out that dummy app for reference.__ To
start it, run

```
git clone https://github.com/simplabs/ember-simple-auth.git
cd ember-simple-auth
yarn install && bower install && ember serve
```

and go to [http://localhost:4200](http://localhost:4200).

## Installation

Installing the library is as easy as:

```bash
ember install ember-simple-auth
```

### Upgrading from ember-cli-simple-auth / pre-1.0 release?
The 1.0 release of ember-simple-auth introduced a lot of breaking changes, but thankfully [the upgrade path isn't too hard](http://log.simplabs.com/post/131698328145/updating-to-ember-simple-auth-10).

## Walkthrough

Once the library is installed, __the session service can be injected wherever
needed in the application__. In order to display login/logout buttons
depending on the current session state, inject the service into the respective
controller or component and __query its
[`isAuthenticated` property](http://ember-simple-auth.com/api/classes/SessionService.html#property_isAuthenticated)
in the template__:

```js
// app/controllers/application.js
import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session')

  …
});
```

```handlebars
{{!-- app/templates/application.hbs --}}
<div class="menu">
  …
  {{#if session.isAuthenticated}}
    <a {{action 'invalidateSession'}}>Logout</a>
  {{else}}
    {{#link-to 'login'}}Login{{/link-to}}
  {{/if}}
</div>
<div class="main">
  {{outlet}}
</div>
```

In the `invalidateSession` action __call the
[session service's `invalidate` method](http://ember-simple-auth.com/api/classes/SessionService.html#method_invalidate)
to invalidate the session__ and log the user out:

```js
// app/controllers/application.js
import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session'),

  …

  actions: {
    invalidateSession() {
      this.get('session').invalidate();
    }
  }
});
```

For authenticating the session, __the session service provides the
[`authenticate` method](http://ember-simple-auth.com/api/classes/SessionService.html#method_authenticate)__
that takes the name of the authenticator to use as well as other arguments
depending on specific authenticator used. __To define an authenticator, add a
new file in `app/authenticators`__ and extend one of the authenticators the
library comes with, e.g.:

```js
// app/authenticators/oauth2.js
import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant';

export default OAuth2PasswordGrant.extend();
```

With that authenticator and a login form like

```handlebars
{{!-- 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>
  {{#if errorMessage}}
    <p>{{errorMessage}}</p>
  {{/if}}
</form>
```

the __session can be authenticated with the
[session service's `authenticate` method](http://ember-simple-auth.com/api/classes/SessionService.html#method_authenticate)__:

```js
// app/controllers/login.js
import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session'),

  actions: {
    authenticate() {
      let { identification, password } = this.getProperties('identification', 'password');
      this.get('session').authenticate('authenticator:oauth2', identification, password).catch((reason) => {
        this.set('errorMessage', reason.error || reason);
      });
    }
  }
});
```

__The session service also provides the
[`authenticationSucceeded`](http://ember-simple-auth.com/api/classes/SessionService.html#event_authenticationSucceeded)
and
[`invalidationSucceeded`](http://ember-simple-auth.com/api/classes/SessionService.html#event_invalidationSucceeded)
events__ that are triggered whenever the session is successfully authenticated
or invalidated (which not only happens when the user submits the login form or
clicks the logout button but also when the session is authenticated or
invalidated in another tab or window of the application). __To have these
events handled automatically, simply mix
[`ApplicationRouteMixin`](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html)
into the application route__:

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

export default Ember.Route.extend(ApplicationRouteMixin);
```

The `ApplicationRouteMixin` automatically maps the session events to the
[`sessionAuthenticated`](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html#method_sessionAuthenticated)
and
[`sessionInvalidated`](http://ember-simple-auth.com/api/classes/ApplicationRouteMixin.html#method_sessionInvalidated)
methods it implements. The `sessionAuthenticated` method will transition to a
configurable route while the `sessionInvalidated` method will reload the page
to clear all potentially sensitive data from memory.

__To make a route in the application accessible only when the session is
authenticated__, mix the
[`AuthenticatedRouteMixin`](http://ember-simple-auth.com/api/classes/AuthenticatedRouteMixin.html)
into the respective route:

```js
// app/routes/protected.js
import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

export default Ember.Route.extend(AuthenticatedRouteMixin);
```

This will make the route (and all of its subroutes) transition to the `login`
route if the session is not authenticated. Add the `login` route in the router
like this:

```js
// app/router.js
Router.map(function() {
  this.route('login');
}
```

The route to transition to if the session is not authenticated can also be
[configured](#configuration) to be another one than `login`.

To prevent a route from being accessed when the session is authenticated (which
makes sense for login and registration routes for example), mix the
[`UnauthenticatedRouteMixin`](http://ember-simple-auth.com/api/classes/UnauthenticatedRouteMixin.html)
into the respective route.

In order to add authorization information to outgoing API requests the
application can define an authorizer. To do so, add a new file to
`app/authorizers`, e.g.:

```js
// app/authorizers/oauth2.js
import OAuth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer';

export default OAuth2Bearer.extend();
```

and use that to authorize a block of code via the
[session service's `authorize`](http://ember-simple-auth.com/api/classes/SessionService.html#method_authorize)
method, e.g.:

```js
this.get('session').authorize('authorizer:oauth2', (headerName, headerValue) => {
  const headers = {};
  headers[headerName] = headerValue;
  Ember.$.ajax('/secret-data', { headers });
});
```

To include authorization info in all Ember Data requests if the session is
authenticated, mix the
[`DataAdapterMixin`](http://ember-simple-auth.com/api/classes/DataAdapterMixin.html)
into the application adapter:

```js
// app/adapters/application.js
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';

export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
  authorizer: 'authorizer:oauth2'
});
```

## The Session Service

The session service is the main interface to the library. It defines the
`authenticate`, `invalidate` and `authorize` methods as well as the session
events as shown above.

It also provides the
__[`isAuthenticated`](http://ember-simple-auth.com/api/classes/SessionService.html#property_isAuthenticated)
as well as the
[`data`]((http://ember-simple-auth.com/api/classes/SessionService.html#property_data))
properties. The latter can be used to get and set the session data__. While the
special `authenticated` section in the session data contains the data that was
acquired by the authenticator when it authenticated the session and is
read-only, all other session data can be written and will also remain in the
session after it is invalidated. It can be used to store all kinds of client
side data that needs to be persisted and synchronized across tabs and windows,
e.g.:

```js
this.get('session').set('data.locale', 'de');
```

## Authenticators

__Authenticators implement the concrete steps necessary to authenticate the
session.__ An application can leverage several authenticators for different
kinds of authentication mechanisms (e.g. the application's own backend server,
external authentication providers like Facebook etc.) while the session is only
ever authenticated with one authenticator at a time. The authenticator to use
is chosen when authentication is triggered via the name it is registered with
in the Ember container:

```js
this.get('session').authenticate('authenticator:some');
```

Ember Simple Auth comes with 3 authenticators:

* [`OAuth2PasswordGrantAuthenticator`](http://ember-simple-auth.com/api/classes/OAuth2PasswordGrantAuthenticator.html): an OAuth 2.0 authenticator that implements the _"Resource Owner Password Credentials Grant Type"_
* [`OAuth2ImplicitGrantAuthenticator`](http://ember-simple-auth.com/api/classes/OAuth2ImplicitGrantAuthenticator.html): an OAuth 2.0 authenticator that implements the _"Implicit Grant Type"_
* [`DeviseAuthenticator`](http://ember-simple-auth.com/api/classes/DeviseAuthenticator.html): an authenticator compatible with the popular Ruby on Rails authentication plugin [devise](https://github.com/plataformatec/devise)
* [`ToriiAuthenticator`](http://ember-simple-auth.com/api/classes/ToriiAuthenticator.html): an authenticator that wraps the [torii library](https://github.com/Vestorly/torii)

To use any of these authenticators in an application, define a new
authenticator in `app/authenticators`, extend if from the Ember Simple Auth
authenticator

```js
// app/authenticators/oauth2.js
import OAuth2PasswordGrantAuthenticator from 'ember-simple-auth/authenticators/oauth2-password-grant';

export default OAuth2PasswordGrantAuthenticator.extend();
```

and invoke the session service's `authenticate` method with the respective
name, specifying more arguments as needed by the authenticator:

```js
this.get('session').authenticate('authenticator:some', data);
```

### Customizing an Authenticator

Authenticators are easily customized by setting the respective properties,
e.g.:

```js
// app/authenticators/oauth2.js
import OAuth2PasswordGrantAuthenticator from 'ember-simple-auth/authenticators/oauth2-password-grant';

export default OAuth2PasswordGrantAuthenticator.extend({
  serverTokenEndpoint: '/custom/endpoint'
});
```

### Implementing a custom Authenticator

Besides extending one of the predefined authenticators, an application can also
implement fully custom authenticators. In order to do that, extend the
[abstract base authenticator](http://ember-simple-auth.com/api/classes/BaseAuthenticator.html)
that Ember Simple Auth comes with and override the
[`authenticate`](http://ember-simple-auth.com/api/classes/BaseAuthenticator.html#method_authenticate),
[`restore`](http://ember-simple-auth.com/api/classes/BaseAuthenticator.html#method_restore)
and (optionally)
[`invalidate`](http://ember-simple-auth.com/api/classes/BaseAuthenticator.html#method_invalidate)
methods:

```js
// app/authenticators/custom.js
import Base from 'ember-simple-auth/authenticators/base';

export default Base.extend({
  restore(data) {
    …
  },
  authenticate(options) {
    …
  },
  invalidate(data) {
    …
  }
});
```

## Authorizers

__Authorizers use the session data acquired by the authenticator to construct
authorization data__ that can be injected into outgoing network requests. As
the authorizer depends on the data that the authenticator acquires,
__authorizers and authenticators have to fit together__.

Ember Simple Auth comes with 2 authorizers:

* [`OAuth2BearerAuthorizer`](http://ember-simple-auth.com/api/classes/OAuth2BearerAuthorizer.html): an OAuth 2.0 authorizer that uses Bearer tokens
* [`DeviseAuthorizer`](http://ember-simple-auth.com/api/classes/DeviseAuthorizer.html): an authorizer compatible with the popular Ruby on Rails authentication plugin [devise](https://github.com/plataformatec/devise)

To use any of these authorizers in an application, define a new authorizer in
`app/authorizers`, extend if from the Ember Simple Auth authorizer

```js
// app/authorizers/oauth2.js
import OAuth2Bearer from 'ember-simple-auth/authorizers/oauth2-bearer';

export default OAuth2Bearer.extend();
```

and invoke the session service's [`authorize`](http://ember-simple-auth.com/api/classes/SessionService.html#method_authorize) method with the respective name:

```js
this.get('session').authorize('authorizer:some', (/*authorization data*/) => {
  // Use authorization data
});
```

__Unlike in previous versions of Ember Simple Auth, authorization will not
happen automatically for all requests the application issues anymore__ but has
to be initiated explicitly via the service.

When using Ember Data you can mix the `DataAdapterMixin` in the application
adapter to automatically authorize all API requests:

```js
// app/adapters/application.js
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';

export default DS.JSONAPIAdapter.extend(DataAdapterMixin, {
  authorizer: 'authorizer:some'
});
```

### Customizing an Authorizer

Authorizers are easily customized by setting the respective properties, e.g.:

```js
// app/authorizers/devise.js
import DeviseAuthorizer from 'ember-simple-auth/authorizers/devise';

export default DeviseAuthorizer.extend({
  identificationAttributeName: 'login'
});
```

### Implementing a custom Authorizer

Besides extending one of the predefined authorizers, an application can also
implement fully custom authorizers. In order to do that, extend the
[abstract base authorizer](http://ember-simple-auth.com/api/classes/BaseAuthorizer.html)
that Ember Simple Auth comes with and override the
[`authorize`](http://ember-simple-auth.com/api/classes/BaseAuthorizer.html#method_authorize)
method:

```js
// app/authorizers/custom.js
import Base from 'ember-simple-auth/authorizers/base';

export default Base.extend({
  authorize(sessionData, block) {
    …
  }
});
```

## Session Stores

Ember Simple Auth __persists the session state via a session store so it
survives page reloads__. There is only one store per application that can be
defined in `app/session-stores/application.js`:

```js
// app/session-stores/application.js
import Cookie from 'ember-simple-auth/session-stores/cookie';

export default Cookie.extend();
```

If the application does not define a session store, the adaptive store which
uses `localStorage` if that is available or a cookie if it is not, will be used
by default. To customize the adaptive store, define a custom store in
`app/session-stores/application.js` that extends it and overrides the
properties to customize.

### Store Types

Ember Simple Auth comes with 4 stores:

#### Adaptive Store

[The adaptive store](http://ember-simple-auth.com/api/classes/AdaptiveStore.html)
stores its data in the browser's `localStorage` if that is available or in a
cookie if it is not; __this is the default store__.

#### `localStorage` Store

[The `localStorage` store](http://ember-simple-auth.com/api/classes/LocalStorageStore.html)
stores its data in the browser's `localStorage`. This is used by the adaptive
store if `localStorage` is available.

#### Cookie Store

[The Cookie store](http://ember-simple-auth.com/api/classes/CookieStore.html)
stores its data in a cookie. This is used by the adaptive store if
`localStorage` is not available. __This store must be used when the
application uses
[FastBoot](https://github.com/ember-fastboot/ember-cli-fastboot).__

#### `sessionStorage` Store

[The `sessionStorage` store](http://ember-simple-auth.com/api/classes/SessionStorageStore.html)
stores its data in the browser's `sessionStorage`. See [the Web Storage docs](
https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) for details on
`sessionStorage` and `localStorage`. [caniuse](http://caniuse.com/#feat=namevalue-storage)
has up-to-date information on browser support of `sessionStorage` and `localStorage`.

#### Ephemeral Store

[The ephemeral store](http://ember-simple-auth.com/api/classes/EphemeralStore.html)
stores its data in memory and thus __is not actually persistent. This store is
mainly useful for testing.__ Also the ephemeral store cannot keep multiple tabs
or windows in sync as tabs/windows cannot share memory.

### Customizing the Store

The session store is easily customized by setting the respective properties,
e.g.:

```js
// app/session-stores/application.js
import AdaptiveStore from 'ember-simple-auth/session-stores/adaptive';

export default AdaptiveStore.extend({
  cookieName: 'my-apps-session-cookie'
});
```

### Implementing a custom Store

Besides using one of the predefined session stores, an application can also
implement fully custom stores. In order to do that, extend the
[abstract base session store](http://ember-simple-auth.com/api/classes/BaseStore.html)
that Ember Simple Auth comes with and implement the
[`persist`](http://ember-simple-auth.com/api/classes/BaseStore.html#method_persist),
[`restore`](http://ember-simple-auth.com/api/classes/BaseStore.html#method_restore)
and
[`clear`](http://ember-simple-auth.com/api/classes/BaseStore.html#method_clear)
methods:

```js
// app/session-stores/application.js
import Base from 'ember-simple-auth/session-stores/base';

export default Base.extend({
  persist() {
    …
  },

  restore() {
    …
  }
});
```

## FastBoot

Ember Simple Auth works with FastBoot out of the box as long as the Cookie
session store is being used. In order to enable the cookie store, define it as
the application store:

```js
// app/session-stores/application.js
import CookieStore from 'ember-simple-auth/session-stores/cookie';

export default CookieStore.extend();
```

If you are using the
[`OAuth2PasswordGrantAuthenticator`](http://ember-simple-auth.com/api/classes/OAuth2PasswordGrantAuthenticator.html),
or
[`DeviseAuthenticator`](http://ember-simple-auth.com/api/classes/DeviseAuthenticator.html),
you must add `node-fetch` to your list of FastBoot whitelisted dependencies
in `package.json`:

```json
{
  "fastbootDependencies": [
    "node-fetch"
  ]
}
```

## Testing

Ember Simple Auth comes with a __set of test helpers that can be used in
acceptance tests__:

* `currentSession(app)`: returns the current session.
* `authenticateSession(app, sessionData)`: authenticates the session; the
  optional `sessionData` argument can be used to mock an authenticator
  response - e.g. a token.
* `invalidateSession(app)`: invalidates the session.

The test helpers can be imported from the `helpers/ember-simple-auth`
module in the application's namespace:

```js
// tests/acceptance/…
import { currentSession, authenticateSession, invalidateSession } from '<app-name>/tests/helpers/ember-simple-auth';
```

## Other guides

* [Managing current User](guides/managing-current-user.md)

## License

Ember Simple Auth is developed by and &copy;
[simplabs GmbH/Marco Otte-Witte](http://simplabs.com) and contributors. It is
released under the
[MIT License](LICENSE).

Ember Simple Auth is not an official part of [Ember.js](http://emberjs.com) and
is not maintained by the Ember.js Core Team.
