Permalink
Browse files

feat(authentication): add support for auth0 login using lock

Adds an Auth0Lock provider class that wraps the Auth0-Lock library.
It activates when the oauthType property is equal to 'auth0-lock',
and expects some peculiar properties in its configuration block
(see the sample config in baseConfig.js).

TODO: proper testing; better way to load it (provider extensibility api)
  • Loading branch information...
pfurini committed May 28, 2016
1 parent 877fa50 commit 97e625e8f271fd5fe72d5f4aed71fe6acfdafe4a
Showing with 106 additions and 14 deletions.
  1. +1 −0 config.js
  2. +1 −11 package.json
  3. +80 −0 src/auth0Lock.js
  4. +10 −3 src/authentication.js
  5. +14 −0 src/baseConfig.js
@@ -12,6 +12,7 @@ System.config({
"aurelia-fetch-client": "npm:aurelia-fetch-client@1.0.0-beta.1.2.1",
"aurelia-logging": "npm:aurelia-logging@1.0.0-beta.1.2.0",
"aurelia-metadata": "npm:aurelia-metadata@1.0.0-beta.1.2.0",
"aurelia-pal": "npm:aurelia-pal@1.0.0-beta.1.2.2",
"aurelia-pal-browser": "npm:aurelia-pal-browser@1.0.0-beta.1.2.0",
"aurelia-path": "npm:aurelia-path@1.0.0-beta.1.2.1",
"aurelia-polyfills": "npm:aurelia-polyfills@1.0.0-beta.1.1.1",
@@ -23,7 +23,6 @@
},
"jspm": {
"registry": "npm",
"jspmPackage": true,
"main": "aurelia-authentication",
"format": "amd",
"directories": {
@@ -35,16 +34,7 @@
"aurelia-fetch-client": "^1.0.0-beta.1.2.1",
"aurelia-logging": "^1.0.0-beta.1.2.0",
"aurelia-metadata": "^1.0.0-beta.1.2.0",
"aurelia-path": "^1.0.0-beta.1.2.1",
"aurelia-router": "^1.0.0-beta.1.2.0",
"extend": "^3.0.0"
},
"peerDependencies": {
"aurelia-api": "^3.0.0-rc1",
"aurelia-dependency-injection": "^1.0.0-beta.1.2.0",
"aurelia-fetch-client": "^1.0.0-beta.1.2.1",
"aurelia-logging": "^1.0.0-beta.1.2.0",
"aurelia-metadata": "^1.0.0-beta.1.2.0",
"aurelia-pal": "^1.0.0-beta.1.2.2",
"aurelia-path": "^1.0.0-beta.1.2.1",
"aurelia-router": "^1.0.0-beta.1.2.0",
"extend": "^3.0.0"
@@ -0,0 +1,80 @@
import {inject} from 'aurelia-dependency-injection';
import {PLATFORM} from 'aurelia-pal';
import extend from 'extend';
import {Storage} from './storage';
import {BaseConfig} from './baseConfig';
@inject(Storage, BaseConfig)
export class Auth0Lock {
constructor(storage, config) {
this.storage = storage;
this.config = config;
this.defaults = {
name: null,
state: null,
scope: null,
scopeDelimiter: null,
redirectUri: null,
clientId: null,
clientDomain: null,
display: 'popup',
lockOptions: {
popup: true
},
popupOptions: null,
responseType: 'token'
};
}
open(options, userData) {
// check pre-conditions
if (typeof PLATFORM.global.Auth0Lock !== 'function') {
throw new Error('Auth0Lock was not found in global scope. Please load it before using this provider.');
}
const provider = extend(true, {}, this.defaults, options);
const stateName = provider.name + '_state';
if (typeof provider.state === 'function') {
this.storage.set(stateName, provider.state());
} else if (typeof provider.state === 'string') {
this.storage.set(stateName, provider.state);
}
this.lock = this.lock || new PLATFORM.global.Auth0Lock(provider.clientId, provider.clientDomain);
const openPopup = new Promise(function(resolve, reject) {
let opts = provider.lockOptions;
opts.popupOptions = provider.popupOptions;
opts.responseType = provider.responseType;
opts.callbackURL = provider.redirectUri;
opts.authParams = opts.authParams || {};
if (provider.scope) opts.authParams.scope = provider.scope;
if (provider.state) opts.authParams.state = this.storage.get(provider.name + '_state');
this.lock.show(provider.lockOptions, (err, profile, tokenOrCode) => {
if (err) {
reject(err);
} else {
resolve({
//NOTE: this is an id token (JWT) and it shouldn't be named access_token
access_token: tokenOrCode
});
}
});
}.bind(this));
return openPopup
.then(lockResponse => {
if (provider.responseType === 'token' ||
provider.responseType === 'id_token%20token' ||
provider.responseType === 'token%20id_token'
) {
return lockResponse;
}
//NOTE: 'code' responseType is not supported, this is an OpenID response (JWT token)
// and code flow is not secure client-side
throw new Error('Only `token` responseType is supported');
});
}
}
@@ -6,14 +6,16 @@ import {BaseConfig} from './baseConfig';
import {Storage} from './storage';
import {OAuth1} from './oAuth1';
import {OAuth2} from './oAuth2';
import {Auth0Lock} from './auth0Lock';
@inject(Storage, BaseConfig, OAuth1, OAuth2)
@inject(Storage, BaseConfig, OAuth1, OAuth2, Auth0Lock)
export class Authentication {
constructor(storage, config, oAuth1, oAuth2) {
constructor(storage, config, oAuth1, oAuth2, auth0Lock) {
this.storage = storage;
this.config = config;
this.oAuth1 = oAuth1;
this.oAuth2 = oAuth2;
this.auth0Lock = auth0Lock;
this.updateTokenCallstack = [];
this.accessToken = null;
this.refreshToken = null;
@@ -225,7 +227,12 @@ export class Authentication {
oauthType = this.config.providers[name].oauthType;
}
const providerLogin = oauthType === '1.0' ? this.oAuth1 : this.oAuth2;
let providerLogin;
if (oauthType === 'auth0-lock') {
providerLogin = this.auth0Lock;
} else {
providerLogin = (oauthType === '1.0' ? this.oAuth1 : this.oAuth2);
}
return providerLogin.open(this.config.providers[name], userData);
}
@@ -249,6 +249,20 @@ export class BaseConfig {
scopeDelimiter: ' ',
oauthType: '2.0',
popupOptions: { width: 1028, height: 529 }
},
auth0: {
name: 'auth0',
oauthType: 'auth0-lock',
clientId: 'your_client_id',
clientDomain: 'your_domain_url',
display: 'popup',
lockOptions: {
popup: true
},
responseType: 'token',
state: function() {
return Math.random().toString(36).substr(2);
}
}
};

0 comments on commit 97e625e

Please sign in to comment.