fix(auth0): Unify authentication via auth0 as provider
This commit is contained in:
committed by
Stuart Taylor
parent
38bcc2e250
commit
ebba8e9c64
@ -1,28 +1,19 @@
|
||||
import { Observable } from 'rx';
|
||||
// import debug from 'debug';
|
||||
import dedent from 'dedent';
|
||||
import { isEmail } from 'validator';
|
||||
|
||||
import {
|
||||
getSocialProvider,
|
||||
getUsernameFromProvider
|
||||
} from '../../server/utils/auth';
|
||||
import { observeMethod, observeQuery } from '../../server/utils/rx';
|
||||
import { wrapHandledError } from '../../server/utils/create-handled-error.js';
|
||||
|
||||
// const log = debug('fcc:models:userIdent');
|
||||
|
||||
export default function(UserIdent) {
|
||||
|
||||
UserIdent.on('dataSourceAttached', () => {
|
||||
UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
|
||||
});
|
||||
// original source
|
||||
// github.com/strongloop/loopback-component-passport
|
||||
// find identity if it exist
|
||||
// if not redirect to email signup
|
||||
// if yes and github
|
||||
// update profile
|
||||
// update username
|
||||
// update picture
|
||||
|
||||
UserIdent.login = function(
|
||||
_provider,
|
||||
authScheme,
|
||||
@ -33,24 +24,44 @@ export default function(UserIdent) {
|
||||
) {
|
||||
const User = UserIdent.app.models.User;
|
||||
const AccessToken = UserIdent.app.models.AccessToken;
|
||||
const provider = getSocialProvider(_provider);
|
||||
options = options || {};
|
||||
if (typeof options === 'function' && !cb) {
|
||||
cb = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
// get the social provider data and the external id from auth0
|
||||
profile.id = profile.id || profile.openid;
|
||||
const auth0IdString = '' + profile.id;
|
||||
const socialExtId = auth0IdString.substring(auth0IdString.indexOf('|') + 1);
|
||||
const provider = auth0IdString.substring(0, auth0IdString.indexOf('|'));
|
||||
const query = {
|
||||
where: {
|
||||
provider: provider,
|
||||
externalId: profile.id
|
||||
externalId: socialExtId
|
||||
},
|
||||
include: 'user'
|
||||
};
|
||||
// get the email from the auth0 (its expected from social providers)
|
||||
const email = (profile && profile.emails && profile.emails[0]) ?
|
||||
profile.emails[0].value : '';
|
||||
if (!isEmail('' + email)) {
|
||||
throw wrapHandledError(
|
||||
new Error('invalid or empty email recieved from auth0'),
|
||||
{
|
||||
message: dedent`
|
||||
Oops... something is not right. We did not find a valid email from your
|
||||
${provider} account. Please try again with a different provider that has an
|
||||
email available with it.
|
||||
`,
|
||||
type: 'info',
|
||||
redirectTo: '/'
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (provider === 'auth0') {
|
||||
if (provider === 'email') {
|
||||
|
||||
const email = profile.emails[0].value;
|
||||
return User.findOne$({ where: { email } })
|
||||
.flatMap(user => {
|
||||
return user ?
|
||||
@ -63,8 +74,8 @@ export default function(UserIdent) {
|
||||
new Error('could not find or create a user'),
|
||||
{
|
||||
message: dedent`
|
||||
Oops... something is not right. We could not find or create a
|
||||
user with that email.
|
||||
Oops... something is not right. We could not find or create a
|
||||
user with that email.
|
||||
`,
|
||||
type: 'info',
|
||||
redirectTo: '/'
|
||||
@ -101,61 +112,17 @@ export default function(UserIdent) {
|
||||
|
||||
return UserIdent.findOne$(query)
|
||||
.flatMap(identity => {
|
||||
if (!identity) {
|
||||
throw wrapHandledError(
|
||||
new Error('user identity account not found'),
|
||||
{
|
||||
message: dedent`
|
||||
We cannot create new user accounts with the deprecated social sign in
|
||||
methods. If you already have an account with us, please sign in with your
|
||||
email address instead.
|
||||
`,
|
||||
type: 'info',
|
||||
redirectTo: '/'
|
||||
}
|
||||
);
|
||||
}
|
||||
const modified = new Date();
|
||||
const user = identity.user();
|
||||
if (!user) {
|
||||
const username = getUsernameFromProvider(provider, profile);
|
||||
return observeQuery(
|
||||
identity,
|
||||
'updateAttributes',
|
||||
{
|
||||
isOrphaned: username || true
|
||||
}
|
||||
)
|
||||
.do(() => {
|
||||
throw wrapHandledError(
|
||||
new Error('user identity is not associated with a user'),
|
||||
{
|
||||
type: 'info',
|
||||
redirectTo: '/',
|
||||
message: dedent`
|
||||
The user account associated with the ${provider} user ${username || 'Anon'}
|
||||
no longer exists.
|
||||
`
|
||||
}
|
||||
);
|
||||
return identity ?
|
||||
Observable.of(identity.user()) :
|
||||
User.findOne$({ where: { email } })
|
||||
.flatMap(user => {
|
||||
return user ?
|
||||
Observable.of(user) :
|
||||
User.create$({ email }).toPromise();
|
||||
});
|
||||
}
|
||||
})
|
||||
.flatMap(user => {
|
||||
|
||||
// identity already exists
|
||||
// find user and log them in
|
||||
identity.credentials = credentials;
|
||||
const attributes = {
|
||||
// we no longer want to keep the profile
|
||||
// this is information we do not need or use
|
||||
profile: null,
|
||||
credentials: credentials,
|
||||
modified
|
||||
};
|
||||
const updateIdentity = observeQuery(
|
||||
identity,
|
||||
'updateAttributes',
|
||||
attributes
|
||||
);
|
||||
const createToken = observeQuery(
|
||||
AccessToken,
|
||||
'create',
|
||||
@ -165,17 +132,24 @@ export default function(UserIdent) {
|
||||
ttl: user.constructor.settings.ttl
|
||||
}
|
||||
);
|
||||
const updateUser = user.update$({
|
||||
email: email,
|
||||
emailVerified: true,
|
||||
emailAuthLinkTTL: null,
|
||||
emailVerifyTTL: null
|
||||
});
|
||||
return Observable.combineLatest(
|
||||
Observable.of(user),
|
||||
updateIdentity,
|
||||
createToken,
|
||||
(user, identity, token) => ({ user, identity, token })
|
||||
updateUser,
|
||||
(user, token) => ({ user, token })
|
||||
);
|
||||
})
|
||||
.subscribe(
|
||||
({ user, identity, token }) => cb(null, user, identity, token),
|
||||
({ user, token }) => cb(null, user, null, token),
|
||||
cb
|
||||
);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
17
sample.env
17
sample.env
@ -3,23 +3,6 @@ MONGOHQ_URL='mongodb://localhost:27017/freecodecamp'
|
||||
|
||||
ROLLBAR_APP_ID='my-rollbar-app-id'
|
||||
|
||||
FACEBOOK_ID=stuff
|
||||
FACEBOOK_SECRET=stuff
|
||||
|
||||
GITHUB_ID=stuff
|
||||
GITHUB_SECRET=stuff
|
||||
|
||||
GOOGLE_ID=stuff
|
||||
GOOGLE_SECRET=stuff
|
||||
|
||||
LINKEDIN_ID=stuff
|
||||
LINKEDIN_SECRET=stuff
|
||||
|
||||
TWITTER_KEY=stuff
|
||||
TWITTER_SECRET=stuff
|
||||
TWITTER_TOKEN=stuff
|
||||
TWITTER_TOKEN_SECRET=stuff
|
||||
|
||||
AUTH0_CLIENT_ID=stuff
|
||||
AUTH0_CLIENT_SECRET=stuff
|
||||
AUTH0_DOMAIN=stuff
|
||||
|
@ -13,63 +13,6 @@ export default {
|
||||
session: true,
|
||||
failureFlash: true
|
||||
},
|
||||
'facebook-login': {
|
||||
provider: 'facebook',
|
||||
module: 'passport-facebook',
|
||||
clientID: process.env.FACEBOOK_ID,
|
||||
clientSecret: process.env.FACEBOOK_SECRET,
|
||||
authPath: '/auth/facebook',
|
||||
callbackURL: '/auth/facebook/callback',
|
||||
callbackPath: '/auth/facebook/callback',
|
||||
useCustomCallback: true,
|
||||
successRedirect: successRedirect,
|
||||
failureRedirect: failureRedirect,
|
||||
scope: ['email'],
|
||||
failureFlash: true
|
||||
},
|
||||
'google-login': {
|
||||
provider: 'google',
|
||||
authScheme: 'oauth2',
|
||||
module: 'passport-google-oauth2',
|
||||
clientID: process.env.GOOGLE_ID,
|
||||
clientSecret: process.env.GOOGLE_SECRET,
|
||||
authPath: '/auth/google',
|
||||
callbackURL: '/auth/google/callback',
|
||||
callbackPath: '/auth/google/callback',
|
||||
useCustomCallback: true,
|
||||
successRedirect: successRedirect,
|
||||
failureRedirect: failureRedirect,
|
||||
scope: ['email', 'profile'],
|
||||
failureFlash: true
|
||||
},
|
||||
'twitter-login': {
|
||||
provider: 'twitter',
|
||||
authScheme: 'oauth',
|
||||
module: 'passport-twitter',
|
||||
authPath: '/auth/twitter',
|
||||
callbackURL: '/auth/twitter/callback',
|
||||
callbackPath: '/auth/twitter/callback',
|
||||
useCustomCallback: true,
|
||||
successRedirect: successRedirect,
|
||||
failureRedirect: failureRedirect,
|
||||
consumerKey: process.env.TWITTER_KEY,
|
||||
consumerSecret: process.env.TWITTER_SECRET,
|
||||
failureFlash: true
|
||||
},
|
||||
'github-login': {
|
||||
provider: 'github',
|
||||
authScheme: 'oauth2',
|
||||
module: 'passport-github',
|
||||
authPath: '/auth/github',
|
||||
callbackURL: '/auth/github/callback',
|
||||
callbackPath: '/auth/github/callback',
|
||||
useCustomCallback: true,
|
||||
successRedirect: successRedirect,
|
||||
failureRedirect: failureRedirect,
|
||||
clientID: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET,
|
||||
failureFlash: true
|
||||
},
|
||||
'auth0-login': {
|
||||
provider: 'auth0',
|
||||
module: 'passport-auth0',
|
||||
@ -83,7 +26,7 @@ export default {
|
||||
useCustomCallback: true,
|
||||
successRedirect: successRedirect,
|
||||
failureRedirect: failureRedirect,
|
||||
scope: ['openid email'],
|
||||
scope: ['openid profile email'],
|
||||
failureFlash: true
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user