These instructions assume you’re using the default Devise configuration and models. As token authentication is not actually part of Devise anymore, there are some customizations necessary on the server side.
First, a new column for the authentication token must be added to the users table:
That authentication token must be auto-generated by the model on creation:
By default, Devise’s sessions controller only responds to HTML request. In order for it to work with Ember Simple Auth it must also respond to JSON. To achieve that, define a custom sessions controller (if HTML responses are not needed the format handling can be left out of course):
and configure Devise to use that controller instead of the default one:
The Rails application must authenticate users by their authentication token and email if present:
The Rails application should also not issue session cookies but authentication
should be done exclusively via the authentication token as described above. The
easiest way to disable sessions in Rails is to add an initializer
config/initializers/session_store.rb
and disable the session store in that:
The backend app also needs to support Cross-Origin Resource Sharing, so you need to install rack-cors
:
Add it to the Gemfile:
In config/application.rb
, add:
Use the console to create a User before moving to the Ember part.
Using ember-cli, create the app:
Make sure you’re using Ember >= 2.0.0
.
Install the addon ember-simple-auth
:
Then run bower install && npm install
.
This example app will have basically 3 pages: a landing page (where we’ll show information about the app), a login page and a dashboard page (only logged users can see).
First, make the application.js
route extend ApplicationRouteMixin
.
The
ApplicationRouteMixin
mixin defines actions that are triggered when authentication is required, when the session has successfully been authenticated or invalidated or when authentication or invalidation fails or authorization is rejected by the server.
Now, the landing page. Create a file named index.hbs
on app/templates/
and move the <h2 id="title">Welcome to Ember</h2>
from app/templates/application.hbs
to that file. Both templates should look like this:
Habemus landing page! On to the login page now.
Using ember g
, generate a route named login
:
That will create two files (app/routes/login.js
and app/templates/login.hbs
), will add a route to app/router.js
and create unit tests as well.
A /login
now exists and you can link to. Add the following code to the bottom of your landing page:
And make login
route extend UnauthenticatedRouteMixin
provided by ESA.
And add some content to app/templates/login.hbs
:
Now, you have to create a login-form component to handle the login.
In app/templates/components/login-form.hbs
, add:
And add the login-form
component on the login template, the app/templates/login.hbs
file should look like this:
The login-form
component calls authenticate
when the form is submitted, but there’s no authenticate
action on it yet. Add it:
As the component alerted, it does not know how to authenticate the session. We have to extend the devise
authenticator ember-simple-auth
gives us.
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.
Create a file named devise.js
on app/authenticators/
and add the following code:
If your app is proxying your API server you don’t need to customize the serverTokenEndpoint
like we did, but if you’re not, you have to.
We will need an authorizer too. Thankfully, ESA provides a Devise authorizer out of the box, you just need to extend it.
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.
Create a file named devise.js
on app/authorizers/
and add the following code:
You also need to tell the application adapter to use it on all Ember Data requests:
Now, you have to update our login-form
component. You need to inject ember-simple-auth’s session and update the authenticate action.
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.
The session store persists the session and all of its data so that it survives a page reload. It also synchronizes the authentication status across multiple tabs or windows so that when the user logs out in one tab or window of the application, all sensitive data is also cleared in other tabs or windows of the same application as well. 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.
You also need to update the 'connect-src'
attribute on contentSecurityPolicy:
Now, you create the dashboard page, make it protected and redirect the user after login or a logged user accessing the root of the application.
Generate the route:
Customize the template with a secret information and add a link to logout:
Now, make app/routes/dashboard.js
inherit from ember-simple-auth’s AuthenticatedRouteMixin
and add a logout action to it:
Last but not least, tell ember-simple-auth
to redirect the user to dashboard if he’s already authenticated and the route the user should go after the being authenticated.
And now the app is working!
That wraps it up! It was a long post, but I hope you managed to make your app work. If you have something to say, hit me up on Twitter, I’m @romulomachado_ there.
See you in the next one!
authenticate
action on app/components/login-form.js
.base
from ENV['ember-simple-auth']
on config/environment.js
. (Thanks @elidupuis for the heads up!)app/routes/login.js
extend UnauthenticatedRouteMixin
. (Thanks Vladimir!)store
from ENV['ember-simple-auth']
on config/enviroment.js
.ember-simple-auth
: 1.0.0 was merged.
ApplicationController
.ApplicationController
, the refactored one was not working. (Thanks @kyleshevlin for pointing it out!)rack-cors
step to server-side setup.