An ember-cli addon for using Auth0 with Ember Simple Auth.
Auth0's lock widget, is a nice way to get a fully functional signup and login workflow into your app.
- Wires up Auth0's Lock.js to work with ember simple auth.
- Lets you work with ember simple auth just like you normally do!
If you don't already have an account, go signup at for free: Auth0
- Create a new app through your dashboard.
- Add
http://localhost:4200
to your Allowed Callback URLs through your dashboard - Done!
__If you are using Auth0.js > 8.x.x make sure to use JsonWebToken Signature Algorithm RS256 in your Clients
settings under the Advanced Settings -> OAuth
tab.
Install this addon with ember-cli ember install ember-simple-auth-auth0
In your config/environment.js
file, you must provide the following properties
- (REQUIRED) - clientID - Grab from your Auth0 Dashboard
- (REQUIRED) - domain - Grab from your Auth0 Dashboard
- (OPTIONAL) - logoutReturnToURL - This can be overridden if you have a different logout callback than the login page. The logoutURL that is actually gets used is constructed as follows:
// config/environment.js
module.exports = function(environment) {
let ENV = {
'ember-simple-auth': {
authenticationRoute: 'login',
auth0: {
clientID: '1234',
domain: 'my-company.auth0.com',
logoutReturnToURL: '/logout',
}
}
};
return ENV;
};
If you are still using content security policy to manage which resources are allowed to be run on your pages. Please add the following CSP rule.
// config/environment.js
ENV['contentSecurityPolicy'] = {
'font-src': "'self' data: https://*.auth0.com",
'style-src': "'self' 'unsafe-inline'",
'script-src': "'self' 'unsafe-eval' https://*.auth0.com",
'img-src': '*.gravatar.com *.wp.com data:',
'connect-src': "'self' http://localhost:* https://your-app-domain.auth0.com"
};
The following is what the session object looks like after the user has been authenticated.
Note: all keys coming back from auth0 are transformed to camelcase for consistency
{
"authenticated": {
"authenticator": "authenticator:auth0-lock",
"profile": {
"email": "[email protected]",
"app_metadata": {
"is_sm_admin": true,
"api_access": true,
"sm3_eligible": true
},
"user_metadata": {
"profile_image": "https://s.gravatar.com/avatar/aaafe9b3923266eacb178826a65e92d1?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatar2%2Fcw.png",
"email": "[email protected]",
"first_name": "bob",
"last_name": "johnson"
},
"email_verified": true,
"clientID": "Yw2Y9D433veMHCred7j0BESjlnwF7ry8",
"updated_at": "2016-11-15T00:49:16.663Z",
"user_id": "auth0|0ca04c34-2247-40f9-b918-292a4bab8995",
"identities": [
{
"user_id": "0bc04c32-2247-40f9-b918-292a4bab8995",
"provider": "auth0",
"connection": "social",
"isSocial": false
}
],
"created_at": "2016-03-29T18:47:22.112Z",
"global_client_id": "IW1j1MbdaRIz0pOwPdN2Ciuh2uIdzfyQ"
},
"accessToken": "BS72xWcch5x2KZQu",
"idToken": "eyJ0eXAiOiJKV1Q1LCJhbGciOiJIUzI1NiJ9.1yJpc3MiOiJodHRwczovL3NpbXBseW1lYXN1cmVkLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHwwYmEwNGMzNC0yMjQ3LTQwZjktYjkxOC0yOTJhNGJhYjg5OTUiLCJhdWQiOiJZd0RZOUQ0MzN2ZU1IQ3JlZDdqMEJFU2psbndGN3J5OCIsImV4cCI6MTQ3OTY3MDk1NywiaWF0IjoxNDc5MTcwOTU3fQ.JFHqL1GElPgY86ujjECXX3TOYjiTiIn-tXB1AV0-j2s",
"idTokenPayload": {
"iss": "https://domain.auth0.com/",
"sub": "auth0|0ba01134-2247-40f9-b918-292a4bab8995",
"aud": "YwDY9D431v1MHCred7j0BESjlnwF7ry8",
"exp": 1479670957,
"iat": 1479170957
}
}
}
You can use this in your templates that have the session service injected.
My logged in user email is {{session.data.authenticated.profile.email}}!
This addon supports native impersonation support. Just follow the instructions on Auth0's documentation and you will be logged in.
https://auth0.com/docs/user-profile/user-impersonation
The new session object will include the following fields
{
"authenticated": {
"authenticator": "authenticator:auth0-url-hash",
...
"profile": {
"impersonated": true,
"impersonator": {
"user_id": "google-oauth2|108251222085688410292",
"email": "[email protected]"
}
}
...
}
}
Here is an example application route:
// app/routes/application.js
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth-auth0/mixins/application-route-mixin';
const {
Route,
RSVP
} = Ember;
export default Route.extend(ApplicationRouteMixin, {
beforeSessionExpired() {
// Do async logic
// Notify the user that they are about to be logged out.
return RSVP.resolve();
}
});
Add the session service to your application controller:
// app/controllers/application.js
import Ember from 'ember';
const {
Controller,
inject: {
service
},
get
} = Ember;
export default Controller.extend({
session: service(),
actions: {
login () {
// Check out the docs for all the options:
// https://auth0.com/docs/libraries/lock/customization
const lockOptions = {
auth: {
params: {
scope: 'openid user_metadata'
}
}
};
get(this, 'session').authenticate('authenticator:auth0-lock', lockOptions);
},
logout () {
get(this, 'session').invalidate();
}
}
});
// app/templates/application.hbs
{{#if session.isAuthenticated}}
<div>
You are currently logged as: {{session.data.authenticated.profile.email}}
</div>
<a href="" {{ action "logout" }}>Logout</a>
{{else}}
<a href="" {{ action "login" }}>Login</a>
{{/if}}
In order to perform passwordless login you need to use authenticator:auth0-lock-passwordless and pass in one of the valid passwordless types.
- sms
- emailcode
- magiclink
- socialOrMagiclink
To see a list of options that can be used with the passwordless authenticator please see auth0-lock-passwordless repo
// app/controllers/application.js
import Ember from 'ember';
const {
Controller,
inject: {
service
},
get
} = Ember;
export default Controller.extend({
session: service(),
actions: {
login () {
// Check out the docs for all the options:
// https://github.com/auth0/lock-passwordless#customization
const lockOptions = {
authParams: {
scope: 'openid user_metadata'
}
};
get(this, 'session').authenticate('authenticator:auth0-lock-passwordless', 'magiclink', lockOptions, (err, email) => {
console.log(`Email link sent to ${email}!`)
});
},
logout () {
get(this, 'session').invalidate();
}
}
});
Note that you can pass in a callback as the last argument. This proxies the lock-passwordless callback call so that the developer can then handle events after a passwordless link has been sent
If you want to acceptance test the auth0 lock there are two things you can do.
- If you are just using the default auth0-lock authenticator then all you have to do is authenticateSession.
- If you are manually invoking the auth0 lock you should use the
showLock
function on the auth0 service and then callmockAuth0Lock
in your test.
// tests/acceptance/login.js
import { test } from 'qunit';
import { mockAuth0Lock } from 'dummy/tests/helpers/ember-simple-auth-auth0';
import { authenticateSession, currentSession } from 'dummy/tests/helpers/ember-simple-auth';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';
moduleForAcceptance('Acceptance | login');
test('visiting /login redirects to /protected page if authenticated', function(assert) {
assert.expect(1);
const sessionData = {
idToken: 1
};
authenticateSession(this.application, sessionData);
visit('/login');
andThen(() => {
let session = currentSession(this.application);
let idToken = get(session, 'data.authenticated.idToken');
assert.equal(idToken, sessionData.idToken);
assert.equal(currentURL(), '/protected');
});
});
test('it mocks the auth0 lock login and logs in the user', function(assert) {
assert.expect(1);
const sessionData = {
idToken: 1
};
mockAuth0Lock(this.application, sessionData);
visit('/login');
andThen(() => {
assert.equal(currentURL(), '/protected');
});
});
Errors come back as a hash in the url. These will be automatically parsed and ember will transition to the error route with two variables set on the model. error and errorDescription
ember g template application-error
See server for an example of an express application getting called by the ember app.
If you are using ember-data
ember g adapter application
import Ember from 'ember';
import DS from 'ember-data';
import DataAdapterMixin from 'ember-simple-auth/mixins/data-adapter-mixin';
const {
computed
} = Ember;
const {
JSONAPIAdapter
} = DS;
export default JSONAPIAdapter.extend(DataAdapterMixin, {
authorizer: 'authorizer:jwt',
});
// app/routes/application.js
import Ember from 'ember';
import ApplicationRouteMixin from 'ember-simple-auth-auth0/mixins/application-route-mixin';
const {
Route,
RSVP
} = Ember;
export default Route.extend(ApplicationRouteMixin, {
model() {
return this.store.findAll('my-model');
}
});
This will make the following request
GET
http://localhost:4200/my-model
Accept: application/vdn+json-api
Authorization: Bearer 123.123123.1231
To make an API request without ember-data, add the user's JWT token to an Authorization
HTTP header:
fetch('/api/foo', {
method: 'GET',
cache: false,
headers: {
'Authorization': 'Bearer <%= "${session.data.authenticated.jwt}" %>'
}
}).then(function (response) {
// use response
});
git clone
this repositorycd ember-simple-auth-auth0
npm install
- Set the environment variable
AUTH0_CLIENT_ID_ID={Your account id}
- Set the environment variable
AUTH0_DOMAIN={Your account domain}
- Grab from your those from the Auth0 Dashboard
ember serve
- Visit your app at http://localhost:4200.
npm test
(Runsember try:each
to test your addon against multiple Ember versions)ember test
ember test --server
ember build
For more information on using ember-cli, visit https://ember-cli.com/.