With Ember Simple Auth 1.0.0 having been released a few days ago, a lot of people will want to upgrade their applications to it so they can finally make the switch to Ember.js 2.0. While quite a big part of the public API has been changed in 1.0.0, updating an application from Ember Simple Auth 0.8.0 or earlier versions is actually not as hard as it might appear at first glance. This post explains the steps that are necessary to bring an application to 1.0.0.
As 1.0.0 marks the first stable release of Ember Simple Auth, upcoming versions will adhere to the Semantic Versioning rule of not including breaking changes in patch level or minor releases. In fact, Ember Simple Auth will follow Ember’s example and only make additive, backwards compatible changes in all 1.x releases and only remove deprecated parts of the library in the next major release.
Ember Simple Auth 1.0.0 is only distributed as an Ember CLI Addon and drops
the previous bower distribution as well as the individual
ember-cli-simple-auth-*
packages. The first step when upgrading to 1.0.0 is to
uninstall these packages from the application. To do that simply remove the
ember-simple-auth
package from bower.json
as well as all
ember-cli-simple-auth-*
packages from packages.json
.
Once the previous versions are uninstalled, install the 1.0.0 release:
ember install ember-simple-auth
With 1.0.0 all modules that it defines now live in the ember-simple-auth
namespace as opposed to the simple-auth
namespace of previous versions. All
the import
statements that import code from Ember Simple Auth need to be
updated accordingly, e.g.
import ApplicationRouteMixin from 'simple-auth/mixins/application-route-mixin';
becomes
import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
Also the modules for the OAuth 2.0 authenticator and authorizer have been
renamed from just oauth2
to oauth2-password-grant
and oauth2-bearer
respectively so that 'simple-auth/authenticators/oauth2'
is now
'ember-simple-auth/authenticators/oauth2-password-grant'
and
'simple-auth/authorizers/oauth2'
is now
'ember-simple-auth/authorizers/oauth2-bearer'
.
With Ember Simple Auth 1.0.0 the session is no longer automatically injected into all routes, controllers and components but instead is now available as an Ember.Service so in all routes, controllers and components that use the session (or back a template that uses it), that session service needs to be injected, e.g.:
import Ember from 'ember';
export default Ember.Controller.extend({
session: Ember.inject.service(),
});
Ember Simple Auth 1.0.0 does not automatically merge all the predefined
authenticators and authorizers into the application anymore but instead
requires authenticators and authorizers the application actually uses to be
defined explicitly. So if you e.g. were previously using the OAuth 2.0
authenticator simply define an authenticator that extends the OAuth 2.0
authenticator in app/authenticators
:
// app/authenticators/oauth2.js
import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant';
export default OAuth2PasswordGrant.extend({
serverTokenRevocationEndpoint: '/revoke',
});
In addition to the renamed module, the signature of the OAuth 2.0 authenticator has changed as well so that it now expects dedicated arguments for the user’s identification and password instead of one object containing both values, so
const credentials = this.getProperties('identification', 'password');
this.get('session').authenticate('authenticator:oauth2', credentials);
becomes
const { identification, password } = this.getProperties(
'identification',
'password',
);
this.get('session').authenticate(
'authenticator:oauth2',
identification,
password,
);
Also authenticators and authorizers are not configured via
config/environment.js
anymore but instead the respective properties are simply
overridden in the extended classes as for the serverTokenRevocationEndpoint
property in the example above.
Ember Simple Auth’s old auto-authorization mechanism was complex (especially
when working with cross origin requests where configuring the
crossOriginWhitelist
was causing big problems for many people) and has been
removed in 1.0.0. Instead authorization is now explicit. To authorize a block
of code use the
session service’s authorize
method,
e.g.:
this.get('session').authorize(
'authorizer:oauth2-bearer',
(headerName, headerValue) => {
xhr.setRequestHeader(headerName, headerValue);
},
);
If the application uses Ember Data, you can authorize all of the requests it
sends to the API by using the new
DataAdapterMixin
,
e.g.:
// 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:application',
});
While previous versions of Ember Simple Auth allowed to configure a custom session class in order to add properties and methods to the session, Ember Simple Auth 1.0.0 makes the session private and only exposes the session service. In order to migrate a custom session class to work with the service there are 2 options.
You can simply extend the session service and add custom properties and methods in the subclass, e.g.:
// app/services/session.js
import Ember from 'ember';
import DS from 'ember-data';
import SessionService from 'ember-simple-auth/services/session';
export default SessionService.extend({
store: Ember.inject.service(),
account: Ember.computed('data.authenticated.account_id', function () {
const accountId = this.get('data.authenticated.account_id');
if (!Ember.isEmpty(accountId)) {
return DS.PromiseObject.create({
promise: this.get('store').find('account', accountId),
});
}
}),
});
You can also create dedicated services that use the session service internally, e.g.:
import Ember from 'ember';
import DS from 'ember-data';
export default Ember.Service.extend({
session: Ember.inject.service('session'),
store: Ember.inject.service(),
account: Ember.computed('session.data.authenticated.account_id', function () {
const accountId = this.get('session.data.authenticated.account_id');
if (!Ember.isEmpty(accountId)) {
return DS.PromiseObject.create({
promise: this.get('store').find('account', accountId),
});
}
}),
});
In this case the session service remains unchanged and whenever you need the
currently authenticated account you’d use the session-account
service to get
that.
Both solutions work fine but the latter results in cleaner code and better separation of concerns.
Previous versions of Ember Simple Auth allowed the session store to be
configured in config/environment.js
. Ember Simple Auth 1.0.0 removes that
configuration setting and will always use the 'application'
session store.
If not overridden by the application that session store will be an instance of
the new
AdaptiveStore
that internally uses the
LocalStorageStore
if localStorage
storage is available and the
CookieStore
if it
is not. To customize the application store, define it in
app/session-stores/application.js
, extend a predefined session store and
customize properties (as done for authenticators and authorizers as described
above) or implement a fully custom store, e.g.:
// app/session-store/application.js
import CookieStore from 'ember-simple-auth/session-stores/cookie';
export default CookieStore.extend({
cookieName: 'my_custom_cookie_name',
});
Ember Simple Auth 1.0.0 will also automatically use the
EphemeralStore
when running tests so there is no need anymore to configure that for the test
environment (in fact the configuration setting has been removed).
While previous versions of Ember Simple Auth automatically injected the test helpers, version 1.0.0 requires them to be imported in the respective acceptance tests, e.g.:
import {
invalidateSession,
authenticateSession,
currentSession,
} from '../helpers/ember-simple-auth';
Also they now take the application instance as a first argument so instead of
authenticateSession();
one would now write
authenticateSession(App);
The
ApplicationRouteMixin
in Ember Simple Auth 1.0.0 now only defines the two methods
sessionAuthenticated
and
sessionInvalidated
as opposed to the previous four actions. If the application overrides any of
these actions it would now have to override these methods.
I hope this gives a good overview of how upgrading an Ember application to Ember Simple Auth 1.0.0 works. There is lots of documentation available in the README and the API Docs. You might also want to check out the dummy application in the github repo and the intro video on the website.