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
Add it to the Gemfile:
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
Install the addon
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
ApplicationRouteMixinmixin 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
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.
ember g, generate a route named
That will create two files (
app/templates/login.hbs), will add a route to
app/router.js and create unit tests as well.
/login now exists and you can link to. Add the following code to the bottom of your landing page:
login route extend
UnauthenticatedRouteMixin provided by ESA.
And add some content to
Now, you have to create a login-form component to handle the login.
And add the
login-form component on the login template, the
app/templates/login.hbs file should look like this:
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
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
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
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
localStorageif 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:
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!
config/environment.js. (Thanks @elidupuis for the heads up!)
UnauthenticatedRouteMixin. (Thanks Vladimir!)
ember-simple-auth: 1.0.0 was merged.
ApplicationController, the refactored one was not working. (Thanks @kyleshevlin for pointing it out!)
rack-corsstep to server-side setup.