This repository has been archived by the owner on Aug 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
k1ng440
authored and
k1ng440
committed
Oct 17, 2016
1 parent
102e8da
commit ce3ffad
Showing
7 changed files
with
391 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,3 +35,4 @@ jspm_packages | |
|
||
# Optional REPL history | ||
.node_repl_history | ||
/typings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,64 @@ | ||
# loopback-auth0 | ||
Loopback middleware for auth0 | ||
|
||
|
||
# Requirements | ||
* Auth0 Secret Key from client | ||
* [Auth0 Management API v2](https://auth0.com/docs/api/management/v2) | ||
|
||
|
||
|
||
# Installation | ||
|
||
* npm | ||
``` | ||
npm install github:k1ng440/loopback-auth0 | ||
``` | ||
|
||
* Create an async boot script | ||
``` | ||
$ slc loopback:boot-script auth0 | ||
> What type of boot script do you want to generate? async | ||
> create server\boot\auth0.js | ||
``` | ||
|
||
* Edit ***server\boot\auth0.js*** and paste following code | ||
|
||
```js | ||
const secretKey = 'AUTH0 SECRET KEY'; | ||
const domain = 'YOUR DOMAIN.auth0.com'; | ||
const password = 'SOME_RANDOM_PASSWORD_FOR_LOOPBACK_USERS'; | ||
const managementConfig = { | ||
"APIKey": "Auth0 management API Key", // get it from https://auth0.com/docs/api/management/v2 | ||
"GlobalClientSecret": // get it from https://auth0.com/docs/api/management/v2 | ||
"token": "Auth0 management API Token" // get it from https://auth0.com/docs/api/management/v2 | ||
} | ||
|
||
|
||
const jwt = require('loopback-auth0')({ | ||
domain: domain, | ||
secretKey: new Buffer(secretKey, 'base64'), | ||
userModel: app.models.User, | ||
password: password, | ||
managementConfig: config.management, | ||
}); | ||
|
||
app.middleware('initial', jwt.parseTokenFromQueryString.bind(jwt)); | ||
app.middleware('initial', jwt.jwtCheck.bind(jwt)); | ||
app.middleware('initial', jwt.getUserInformation.bind(jwt)); | ||
app.middleware('initial', jwt.mapUser.bind(jwt)); | ||
|
||
``` | ||
|
||
|
||
# Issue Reporting | ||
If you have found a bug or if you have a feature request, please report them at this repository issues section | ||
|
||
|
||
# Auther | ||
[***Asaduzzaman Pavel***](http://www.codegenie.co) | ||
|
||
|
||
# License | ||
|
||
This project is licensed under the MIT license. See the LICENSE file for more info. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
const debug = require('debug')('loopback:jwt'); | ||
const expressJwt = require('express-jwt'); | ||
const Promise = require('bluebird'); | ||
const loopbackUser = require('./loopbackUser'); | ||
const extend = require('xtend'); | ||
const Profile = require('./profile'); | ||
const assert = require('assert'); | ||
const ManagementClient = require('auth0').ManagementClient; | ||
|
||
class LoopbackJwt extends loopbackUser { | ||
|
||
constructor(options) { | ||
super(options); | ||
|
||
assert(options, 'Options must be defined'); | ||
assert(options.secretKey, 'Options.secretKey must be defined'); | ||
assert(options.password, 'Options.password must be defined'); | ||
|
||
this.options = { | ||
secretKey: '', | ||
credentialsRequired: false, | ||
algorithms: ['RS256', 'HS256'], | ||
beforeCreate: null, | ||
}; | ||
|
||
this.userMap = {}; | ||
|
||
this.options = extend(this.options, options); | ||
|
||
this.jwtCheck = expressJwt({ | ||
algorithms: this.options.algorithms, | ||
secret: this.options.secretKey, | ||
credentialsRequired: false, | ||
getToken: options.getToken, | ||
}); | ||
|
||
this.management = new ManagementClient({ | ||
token: this.options.managementConfig.token, | ||
domain: this.options.domain, | ||
}); | ||
} | ||
|
||
parseTokenFromQueryString(req, res, next) { | ||
const accessToken = req.query.access_token; | ||
if (accessToken) { | ||
delete req.query.access_token; | ||
req.headers.authorization = 'Bearer ' + accessToken; | ||
debug( | ||
'parseTokenFromQueryString', | ||
'found token in query string. attached to headers' | ||
); | ||
} | ||
|
||
next(); | ||
}; | ||
|
||
getUserInformation(req, res, next) { | ||
if (!req.user) { | ||
debug('no current user context found.'); | ||
return next(); | ||
} | ||
|
||
let that = this; | ||
this.management.users.get({ | ||
id: req.user.sub, | ||
}, function (err, user) { | ||
req.user = new Profile(user, that.options.userModel); | ||
next(); | ||
}); | ||
} | ||
|
||
mapUser(req, res, next) { | ||
if (!req.user) { | ||
debug('no current user context found.'); | ||
return next(); | ||
} | ||
|
||
this.user = req.user; | ||
|
||
debug('attempting to map user [%s]', this.user.email); | ||
|
||
const token = this.userMap[this.user.email]; | ||
|
||
if (!token) { | ||
this.loginUser() | ||
.then(token => { | ||
debug('mapped existing user [%s]', token.id); | ||
this.userMap[this.user.email] = token; | ||
req.accessToken = token; | ||
next(); | ||
}) | ||
.catch((e) => { | ||
debug('login error', e); | ||
|
||
this.createUser(req) | ||
.then(token => { | ||
this.userMap[this.user.email] = token; | ||
req.accessToken = token; | ||
next(); | ||
}) | ||
.catch(e => { | ||
debug('Error while creating error', e); | ||
next(); | ||
}); | ||
}); | ||
} else { | ||
debug('found existing token [%s]', token.id); | ||
req.accessToken = token; | ||
next(); | ||
} | ||
} | ||
|
||
} | ||
|
||
module.exports = (options) => { | ||
return new LoopbackJwt(options); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
const debug = require('debug')('loopback:jwt'); | ||
|
||
class loopbackUser { | ||
createUser() { | ||
debug('creating new user'); | ||
|
||
return new Promise((resolve, reject) => { | ||
const newUserData = { | ||
firstName: this.user.name.givenName, | ||
lastName: this.user.name.familyName, | ||
auth0Identifier: this.user.id, | ||
email: this.user.email, | ||
password: this.options.password, | ||
}; | ||
|
||
if (typeof this.options.beforeCreate === 'function') { | ||
this.options.beforeCreate(newUserData, user); | ||
} | ||
|
||
this.options.userModel.create(newUserData) | ||
.then(newUser => { | ||
debug('new user created [%s]', newUser.email); | ||
this.loginUser() | ||
.then(token => { | ||
resolve(token); | ||
}).catch(e => { | ||
debug('error while try to login after creating user', | ||
e); | ||
reject(e); | ||
}); | ||
}) | ||
.catch(e => { | ||
debug('error creating user', e); | ||
reject(e); | ||
}); | ||
}); | ||
} | ||
|
||
loginUser() { | ||
debug('attempting to login user [%s]', this.user.email); | ||
return this.options.userModel.login({ | ||
email: this.user.email, | ||
password: this.options.password, | ||
}); | ||
} | ||
}; | ||
|
||
module.exports = loopbackUser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
{ | ||
"name": "loopback-auth0", | ||
"version": "0.0.5", | ||
"description": "Auth0 middleware for auth0", | ||
"main": "jwt.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/k1ng440/loopback-auth0.git" | ||
}, | ||
"keywords": [ | ||
"Auth0", | ||
"loopback", | ||
"strongloop", | ||
"oauth2", | ||
"oauth" | ||
], | ||
"author": "Asaduzzaman Pavel", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/k1ng440/loopback-auth0/issues" | ||
}, | ||
"homepage": "https://github.com/k1ng440/loopback-auth0#readme", | ||
"dependencies": { | ||
"auth0": "^2.5.0", | ||
"bluebird": "^3.4.6", | ||
"express-jwt": "^5.1.0", | ||
"xtend": "^4.0.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
class Profile { | ||
constructor(data, userModel) { | ||
this.data = data; | ||
this.userModel = userModel; | ||
|
||
if (data.identities) { | ||
this.provider = data.identities[0].provider; | ||
} | ||
|
||
this.displayName = data.name; | ||
this.id = this.getId(); | ||
this.email = this.getEmail(); | ||
this.isEmailVerified = this.isEmailVerified(); | ||
this.getDescription(); | ||
|
||
this.name = { | ||
familyName: data.family_name, | ||
givenName: data.given_name, | ||
}; | ||
|
||
if (data.emails) { | ||
this.emails = data.emails.map(email => ({ | ||
value: email, | ||
})); | ||
} else if (data.email) { | ||
this.emails = [{ | ||
value: data.email, | ||
}]; | ||
} | ||
|
||
|
||
//copy these fields | ||
let copy = ['picture', | ||
'locale', | ||
'nickname', | ||
'gender', | ||
'identities', | ||
]; | ||
|
||
copy.filter(k => k in data).forEach(k => { | ||
this[k] = data[k]; | ||
}); | ||
} | ||
|
||
getId() { | ||
return typeof this.data.user_id !== undefined ? | ||
this.data.user_id : | ||
this.data.sub; | ||
} | ||
|
||
getUserName() { | ||
return new Promise((resolve, reject) => { | ||
let username = ''; | ||
let available = false; | ||
|
||
if (this.data.username) { | ||
username = this.data.username; | ||
} else if (this.data.screen_name) { | ||
username = this.data.username; | ||
} | ||
|
||
if (_.empty(useername)) { | ||
username = this.data.name.replace(' ', ''); | ||
} | ||
|
||
while (available === false) { | ||
this.userModel.count({ | ||
username: username, | ||
}, function(err, count) { | ||
if (err) { | ||
debug('Error while counting user', err); | ||
return reject(false); | ||
} | ||
|
||
available = count > 0; | ||
|
||
if (available === true) { | ||
resolve(username); | ||
} else { | ||
username = username + _.random(0, 5000); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
isEmailVerified() { | ||
return (typeof this.data.email_verified !== undefined) && | ||
this.data.email_verified === true; | ||
} | ||
|
||
getEmail() { | ||
let id = null; | ||
if (this.data.email) { | ||
id = this.data.email; | ||
} else { | ||
const usersplit = this.getId(user).split('|'); | ||
id = usersplit[1] + '@' + 'change_this_email.com'; | ||
} | ||
|
||
return id; | ||
} | ||
|
||
getDescription() { | ||
let description; | ||
|
||
if (this.headline) { | ||
description = this.headline; | ||
} else if (this.description) { | ||
description = this.description; | ||
} else if (this.bio) { | ||
description = this.bio; | ||
} else if (this.about) { | ||
description = this.data.about; | ||
} | ||
|
||
this.description = description; | ||
|
||
return description; | ||
} | ||
} | ||
|
||
module.exports = Profile; |
Oops, something went wrong.