Skip to content

Commit

Permalink
Merge branch 'michaelrkn-patch-1' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
Marco Otte-Witte committed May 12, 2014
2 parents b709670 + 02e1cc3 commit 2737025
Showing 1 changed file with 93 additions and 43 deletions.
136 changes: 93 additions & 43 deletions packages/ember-simple-auth-devise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,99 @@ This is an extension to the Ember.SimpleAuth library that provides an
authenticator and an authorizer that are compatible with customized
installations of [Devise](https:/plataformatec/devise).

## Server-side setup

As token authentication is not actually part of Devise anymore, there are some
customizations necessary on the server side. Most of this walk-through is
adapted from [José Valim's gist on token authentication]
(https://gist.github.com/josevalim/fb706b1e933ef01e4fb6).

First, you must add a colunm to your database in which to store the
authentication token:

```ruby
class AddAuthenticationTokenToUser < ActiveRecord::Migration
def change
add_column :users, :authentication_token, :string
end
end
```

Then, you must set up your model to generate the token:

```ruby
class User < ActiveRecord::Base
...
before_save :ensure_authentication_token

def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end

private

def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.where(authentication_token: token).first
end
end
end
```

When a user signs in using Ember, requests are made with a JSON API.
Unfortunately, Devise does not give the responses we need in JSON, so we must
make our own controller:

```ruby
class SessionsController < Devise::SessionsController
def create
self.resource = warden.authenticate!(auth_options)
sign_in(resource_name, resource)
response = {
auth_token: resource.authentication_token,
auth_email: resource.email
}
render json: response, status: 201
end
end
```

Then, we need to tell Devise to use this controller instead of its default:

```ruby
MyRailsApp::Application.routes.draw do
devise_for :users, controllers: {sessions: "sessions"}
...
end
```

Finally, we have to authenticate each subsequent request:

```ruby
class ApplicationController < ActionController::Base
before_filter :authenticate_user_from_token!

private

def authenticate_user_from_token!
token = request.headers['auth-token'].to_s
email = request.headers['auth-email'].to_s
return unless token && email

user = User.find_by_email(email)

if user && Devise.secure_compare(user.authentication_token, token)
sign_in user, store: false
end
end
end
```

Now, we can get on to configuring the Ember side of things.

## The Authenticator

In order to use the Devise authenticator (see the
Expand Down Expand Up @@ -40,24 +133,6 @@ App.LoginController = Ember.Controller.extend(Ember.SimpleAuth.LoginControllerMi
{ authenticatorFactory: 'ember-simple-auth-authenticator:devise' });
```

As token authentication is not actually part of Devise anymore, there are some
customizations necessary on the server side. In order for the authentication to
work it has to include the user's auth token and email in the JSON response for
session creation:

```ruby
class SessionsController < Devise::SessionsController
def create
resource = resource_from_credentials
data = {
auth_token: resource.authentication_token,
auth_email: resource.email
}
render json: data, status: 201
end
end
```

## The Authorizer

The authorizer (see the
Expand All @@ -75,28 +150,3 @@ Ember.Application.initializer({
}
});
```

As token authentication is not actually part of Devise anymore, the server
needs to implement a custom authentication method that uses the provided email
and token to look up the user (see
[discussion here](https://gist.github.com/josevalim/fb706b1e933ef01e4fb6)):

```ruby
class ApplicationController < ActionController::API
before_filter :authenticate_user_from_token!

private

def authenticate_user_from_token!
token = request.headers['auth-token'].to_s
email = request.headers['auth-email'].to_s
return unless token && email

user = User.find_by_email(email)

if user && Devise.secure_compare(user.authentication_token, token)
sign_in user, store: false
end
end
end
```

0 comments on commit 2737025

Please sign in to comment.