Skip to content

Commit

Permalink
feat(social-login): enable social login via existing accounts
Browse files Browse the repository at this point in the history
- add facebook login with passport
- add google login with passport
- add twitter login with passport

[Finishes #166789873]
  • Loading branch information
Karangwa Hirwa Julien authored and Karangwa Hirwa Julien committed Jul 16, 2019
1 parent d0c2a88 commit 1984b64
Show file tree
Hide file tree
Showing 16 changed files with 1,089 additions and 604 deletions.
39 changes: 26 additions & 13 deletions example.env
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
DATABASE_USERNAME_DEV="your-database-username"
DATABASE_PASSWORD="your-database-password"
DATABASE_USERNAME_DEV="your_dev_db_username"
DATABASE_URL=""
DATABASE_PASSWORD="your_dev_db_password"

DATABASE_USERNAME_TEST="your-database-username-for-test"
DATABASE_PASSWORD_TEST="your-postgres-password-test"
HEROKU_DATABASE_USERNAME="jgxfkdjw"
HEROKU_SECRET_KEY="LmbmTy8mqqZEAsmDfKrugdecYNqzeBJ1"
HEROKU_HOST="raja.db.elephantsql.com"
HEROKU_DATABASE="jgxfkdjw"

SENDGRID_API_KEY="insert your send grid token"
SECRET_JWT_KEY="your-own-secret-key"
SECRET_KEY="your-database-password"
SENDGRID_API_KEY="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"
HOST="https://ah-lobos-backend-swagger.herokuapp.com"
DATABASE_PASSWORD_TEST="your_test_db_password"
DATABASE_USERNAME_TEST="your_test_db_username"
SECRET_JWT_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IkthcmFuZ3dhIEhpcndhIEp1bGllbiIsImVtYWlsIjoianVsaXVzaGlyd2FAZ21haWwuY29tIiwiaWF0IjoxNTYyMzA3NDEzLCJleHAiOjE1NjIzOTM4MTN9.vooQWDbNtRRMx4LVZM7n6O2rrUjmfGhWfWnOuppxj9I"
EMAIL="your_email"
PASSWORD="your_password"
SECRET="your_secret"

HEROKU_DATABASE_USERNAME="heroku-database-username"
HEROKU_SECRET_KEY="heroku-database-password"
HEROKU_HOST="heroku-host"
HEROKU_DATABASE="heroku-database-name"

HOST="127.0.0.1:7000"
GMAIL_APP_ID="207391721395-nr9q4f02giavmn6bj91lgosf6ordht9h.apps.googleusercontent.com"
GMAIL_APP_SECRET="nfjp3BycPRO-kmExVAMSZjqu"
FACEBOOK_APP_ID="1245296778980169"
FACEBOOK_APP_SECRET="e735b5c122dbaa24dd5d71c20b55062f"
SECRET="23G4HJ5K6L9876K5JH4G"
TWITTER_APP_ID="fuwF7UbQaKoJqI0KR68Yaqbyj"
TWITTER_APP_SECRET="4e6IHRuSdKfyMeEgQNAfsla3oQNXumsBKCwEMcJcsjPtRfBJhA"
TWITTER_ACCESS_TOKEN="1063823892-tZLv5zh2kwpWZoEPRZrrXRVD3EvMUsO0VqB7DVS"
TWITTER_ACCESS_SECRET="cCJmqIE7Gf2xuttD37A4uzdn1GRGuDTVjrb2goPyJre4j"
CALLBACK="http://127.0.0.1:7000/auth/twitter/callback"

CLOUDINARY_CLOUD_NAME="username"
CLOUDINARY_API_KEY="api-key"
CLOUDINARY_API_SECRET="api-secret"

15 changes: 12 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,35 @@
"license": "MIT",
"dependencies": {
"@hapi/joi": "^15.1.0",
"@rucken/core-nestjs": "^1.0.12",
"@sendgrid/mail": "^6.4.0",
"bcrypt": "^3.0.6",
"body-parser": "^1.19.0",
"cloudinary": "^1.14.0",
"cors": "^2.8.5",
"datauri": "^2.0.0",
"multer": "^1.4.1",
"dotenv": "^6.2.0",
"ejs": "^2.6.1",
"errorhandler": "^1.5.0",
"express": "^4.17.1",
"express-session": "^1.15.6",
"express-session": "^1.16.2",
"googleapis": "^40.0.1",
"jsonwebtoken": "^8.5.1",
"method-override": "^2.3.10",
"methods": "^1.1.2",
"moment": "^2.24.0",
"morgan": "^1.9.1",
"nodemailer": "^6.2.1",
"multer": "^1.4.1",
"node-cron": "^2.0.3",
"nodemailer": "^6.2.1",
"nyc": "^14.1.1",
"passport": "^0.4.0",
"passport-facebook": "^3.0.0",
"passport-google-oauth20": "^2.0.0",
"passport-local": "^1.0.0",
"passport-mock": "0.0.3",
"passport-mocked": "^1.3.0",
"passport-twitter": "^1.0.4",
"pg": "^7.11.0",
"pg-hstore": "^2.3.3",
"regenerator-runtime": "^0.13.2",
Expand Down
117 changes: 117 additions & 0 deletions src/controllers/socialLogin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import dotenv from 'dotenv';
import model from '../db/models';
import processToken from '../helpers/processToken';

const { Users } = model;

dotenv.config();

/**
* User Information are saved here
*/
class UserInfo {
/**
*
* @param {Object} req
* @param {Object} res
* @returns {Object} response after user signin
*/
static async googleLogin(req, res) {
const { displayName } = req.user;
const newUser = await Users.create({
username: displayName,
email: req.user.emails[0].value,
image: req.user.photos[0].value,
isVerified: req.user.emails[0].verified,
socialId: req.user.id,
provider: 'google',
hash: process.env.DEFAULT_PASSWORD
});
if (newUser) {
const {
dataValues: {
id, username, email
}
} = newUser;
const token = await processToken.signToken(newUser.dataValues);
return res.status(200).json({
message: `Welcome to Authors Haven ${displayName} `,
data: {
token, id, username, email
},
});
}
}

/**
*
* @param {Object} req
* @param {Object} res
* @returns {Object} user successfully logged in
*/
static async facebookLogin(req, res) {
const { displayName } = req.user;
const newUser = await Users.create({
username: displayName,
email: req.user.emails[0].value,
image: req.user.photos[0].value,
isVerified: true,
socialId: req.user.id,
provider: 'facebook',
hash: process.env.DEFAULT_PASSWORD
});
if (newUser) {
const {
dataValues: {
id, username, email
}
} = newUser;
const token = await processToken.signToken(newUser.dataValues);
return res.status(200).json({
message: `Welcome to Authors Haven ${displayName} `,
data: {
token, id, username, email
},
});
}
}

/**
*
* @param {Object} req
* @param {Object} res
* @return {Object} user logged in
*/
static async twitterLogin(req, res) {
const {
displayName
} = req.user;

// eslint-disable-next-line no-unused-expressions
const newUser = await Users.create({
username: req.user.username,
email: `${req.user.username}@gmail.com`,
image: req.user.photos[0].value,
isVerified: true,
socialId: req.user.id,
provider: 'twitter',
hash: process.env.DEFAULT_PASSWORD
});
if (newUser) {
const {
dataValues: {
id, username
}
} = newUser;
const token = await processToken.signToken(newUser.dataValues);
return res.status(200).json({
message: `Welcome to Authors Haven ${displayName} `,
data: {
token, id, username
},
});
}
}
}

export default UserInfo;
23 changes: 23 additions & 0 deletions src/db/config/auth/facebook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import passport from 'passport';
import FacebookStrategy from 'passport-facebook';
import config from '../envirnoment';

passport.use(new FacebookStrategy({
clientID: config.facebook_app_id,
clientSecret: config.facebook_app_secret,
callbackURL:`https://ah-lobos-backend-swagger.herokuapp.com/auth/facebook/callback`,
profileFields: ['id', 'displayName', 'photos', 'email']
},
(accessToken, refreshToken, profile, done) => {
done(null, profile);
}));

passport.serializeUser((user, done) => {
done(null, user);
});

passport.deserializeUser((user, done) => {
done(null, user);
});

export default passport;
16 changes: 16 additions & 0 deletions src/db/config/auth/google.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import passport from 'passport';
import GoogleStrategy from 'passport-google-oauth20';
import config from '../envirnoment';

passport.use(new GoogleStrategy({
clientID: config.google_app_id,
clientSecret: config.google_app_secret,
includeEmail: true,
callbackURL: `${config.host}/auth/google/callback`
},
(accessToken, refreshToken, profile, done) => {
done(null, profile);
}
));

export default passport;
15 changes: 15 additions & 0 deletions src/db/config/auth/twitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import passport from 'passport';
import TwitterTokenStrategy from 'passport-twitter';
import config from '../envirnoment';

passport.use(new TwitterTokenStrategy({
consumerKey: config.twitter_app_id,
consumerSecret: config.twitter_app_secret,
callbackURL: config.twitter_callback
},
(token, tokenSecret, profile, done) => {
done(null, profile);
}
));

export default passport;
17 changes: 17 additions & 0 deletions src/db/config/envirnoment.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import dotenv from 'dotenv';
import { eventNames } from 'cluster';

dotenv.config();

Expand All @@ -15,4 +16,20 @@ envConfig.db_password_pro = process.env.HEROKU_SECRET_KEY;
envConfig.db_host_pro = process.env.HEROKU_HOST;
envConfig.db_database_pro = process.env.HEROKU_DATABASE;

envConfig.send_grid_key = process.env.SendGridApiKey;
envConfig.host = process.env.HOST;
envConfig.token = process.env.SECRET_JWT_KEY;
envConfig.email = process.env.EMAIL;
envConfig.password = process.env.PASSWORD;
envConfig.facebook_app_id = process.env.FACEBOOK_APP_ID;
envConfig.facebook_app_secret = process.env.FACEBOOK_APP_SECRET;
envConfig.secret = process.env.SECRET;
envConfig.google_app_id = process.env.GMAIL_APP_ID;
envConfig.google_app_secret = process.env.GMAIL_APP_SECRET;
envConfig.twitter_app_id = process.env.TWITTER_APP_ID;
envConfig.twitter_app_secret = process.env.TWITTER_APP_SECRET;
envConfig.twitter_access_token = process.env.TWITTER_ACCESS_TOKEN;
envConfig.twitter_access_secret = process.env.TWITTER_ACCESS_SECRET;
envConfig.twitter_callback = process.env.CALLBACK;

export default envConfig;
9 changes: 9 additions & 0 deletions src/db/migrations/20190625140719-create-users.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,16 @@ module.exports = {
isVerified: {
type: Sequelize.BOOLEAN
},
socialId: {
allowNull: true,
type: Sequelize.STRING
},
provider: {
allowNull: true,
type: Sequelize.STRING
},
hash: {
allowNull: true,
type: Sequelize.STRING
},
createdAt: {
Expand Down
19 changes: 18 additions & 1 deletion src/db/models/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,24 @@ export default (sequelize, DataTypes) => {
isVerified: {
type: DataTypes.BOOLEAN
},
hash: DataTypes.STRING
socialId: {
allowNull: {
args: true
},
type: DataTypes.STRING
},
provider: {
allowNull: {
args: true
},
type: DataTypes.STRING
},
hash: {
allowNull: {
args: true
},
type: DataTypes.STRING
}
}, {
hooks: {
beforeCreate: async (user) => {
Expand Down
17 changes: 16 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import logger from 'morgan';
import bodyParser from 'body-parser';
import swaggerUI from 'swagger-ui-express';
import cron from 'node-cron';
import passport from 'passport';
import session from 'express-session';
import swaggerJSDoc from '../swagger.json';
import routes from './routes/api/index';
import config from './db/config/envirnoment';
Expand All @@ -16,8 +18,21 @@ app.use(logger('dev')); // log requests to the console
// Parse incoming requests data
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
secret: config.secret,
resave: true,
saveUninitialized: true
}));
app.use(session({
secret: config.secret,
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(routes);
// cron fro deleting blacklist tokens
// cron from deleting blacklist tokens
cron.schedule('* * * * *', () => {
deleteBlacklist();
});
Expand Down
16 changes: 16 additions & 0 deletions src/middlewares/socialTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export default (req, res, next) => {
req.user = {
id: req.body.id,
displayName: 'Karangwa Hirwa Julien',
name: { familyName: 'Karangwa Hirwa', givenName: 'Julien' },
emails:
[{ value: req.body.email, verified: true }],
photos:
[{
value:
'https://lh4.googleusercontent.com/-FZSypt5JyRU/AAAAAAAAAAI/AAAAAAAAAAA/ACHi3repeJYC3C7JQWReWg7zqfLcOxh0Qg/mo/photo.jpg'
}],
provider: 'google'
};
next();
};
Loading

0 comments on commit 1984b64

Please sign in to comment.