Skip to content

Commit

Permalink
[ft-#166240824] Enable Social Login via Google, Facebook and twitter
Browse files Browse the repository at this point in the history
  • Loading branch information
Ramadhan authored and Ramadhan committed Jun 12, 2019
1 parent 493d3a3 commit 9e77be6
Show file tree
Hide file tree
Showing 13 changed files with 335 additions and 20 deletions.
8 changes: 7 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,10 @@ PORT=theServerListeningPort
DEV_DB_URL=TheDevDatabaseConnectionUrl__Format:postgres://user:pass@host:5432/development_dbname
TEST_DB_URL=TheTestDatabaseConnectionUrl__Format:postgres://user:pass@host:5432/test_dbname
DB_URL=TheStaggingDatabaseConnectionUrl__Format:postgres://user:pass@host:5432/dbname
DB_URL=TheProductionDatabaseConnectionUrl__Format:postgres://user:pass@host:5432/dbname
DB_URL=TheProductionDatabaseConnectionUrl__Format:postgres://user:pass@host:5432/dbname


FACEBOOK passport
clientID=FACEBOOK_APP_ID,
clientSecret=FACEBOOK_APP_SECRET,
callbackURL="http://www.example.com/auth/facebook/callback"
12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,31 @@
"nyc": "^14.1.1"
},
"dependencies": {
"babel-plugin-istanbul": "^5.1.2",
"@babel/cli": "^7.4.4",
"@babel/core": "^7.4.5",
"@babel/node": "^7.4.5",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.4.5",
"@babel/register": "^7.4.4",
"babel-plugin-istanbul": "^5.1.2",
"body-parser": "^1.18.3",
"chai-http": "^4.3.0",
"cors": "^2.8.5",
"dotenv": "^8.0.0",
"expect": "^24.8.0",
"express": "^4.16.4",
"express-session": "^1.16.2",
"jsonwebtoken": "^8.5.1",
"morgan": "^1.9.1",
"passport": "^0.4.0",
"passport-facebook": "^3.0.0",
"passport-google-oauth": "^2.0.0",
"passport-pinterest": "^1.0.0",
"passport-twitter": "^1.0.4",
"pg": "^7.11.0",
"sequelize": "^5.8.7",
"sinon": "^7.3.2",
"sinon-chai": "^3.3.0",
"swagger-node-express": "^2.1.3",
"swagger-ui-express": "^4.0.6"
},
Expand Down
5 changes: 2 additions & 3 deletions src/api/controllers/db.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ export default {
},

get: async (req, res) => {
const m = await models.Test.findAll({
});
const m = await models.Test.findAll({});
return res.status(200).send({
data: m,
data: m
});
},

Expand Down
102 changes: 102 additions & 0 deletions src/api/controllers/socialAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import jwt from 'jsonwebtoken';
import model from '../models';

const { User } = model;

/**
*
*
* @class socialLogin
*/
class socialLogin {
/**
* signup via facebook
* login via facebook
*
* @static
* @param {object} req - request object
* @param {object} res - response object
* @memberof socialLogin
* @returns {object} - the response body
*/
static async socialFacebookAuth(req, res) {
let findIfExist = await User.findOne({
where: {
uniqueId: req.user.id
}
});
if (!findIfExist) {
findIfExist = User.create({
firstName: req.user.name.givenName,
lastName: req.user.name.familyName,
userName: req.user.username,
profileImage: req.user.photos[0].value,
provider: req.user.provider,
uniqueId: req.user.id
});
}
const token = jwt.sign({ id: findIfExist.id }, 'secret', { expiresIn: '1d' });
res.json({ user: { ...findIfExist.get(), token } });
}

/**
* signup user via Google
* login user via Google
*
* @static
* @param {object} req - request object
* @param {object} res - request response
* @memberof socialLogin
* @returns {object} - the response body
*/
static async socialGoogleAuth(req, res) {
let findIfExist = await User.findOne({
where: {
uniqueId: req.user.id
}
});
if (!findIfExist) {
findIfExist = User.create({
firstName: req.user.name.familyName,
lastName: req.user.name.givenName,
userName: req.user.displayName,
email: req.user.emails[0].value,
profileImage: req.user.photos[0].value,
provider: req.user.provider,
uniqueId: req.user.id
});
}
const token = jwt.sign({ id: findIfExist.id }, 'secret', { expiresIn: '1d' });
res.json({ user: { ...findIfExist.get(), token } });
}

/**
* signup user via Twitter
* login user via Twitter
*
* @static
* @param {object} req - request object
* @param {object} res - request response
* @memberof socialLogin
* @returns {object} - the response body
*/
static async socialtwitterAuth(req, res) {
let findIfExist = await User.findOne({
where: {
uniqueId: req.user.id
}
});
if (!findIfExist) {
findIfExist = User.create({
userName: req.user.username,
profileImage: req.user.photos[0].value,
provider: req.user.provider,
uniqueId: req.user.id
});
}
const token = jwt.sign({ id: findIfExist.id }, 'secret', { expiresIn: '1d' });
res.json({ user: { ...findIfExist.get(), token } });
}
}

export default socialLogin;
8 changes: 4 additions & 4 deletions src/api/models/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@

import Sequelize from 'sequelize';
import environments from '../../configs/environnements';
import { currentEnv } from '../../configs/environnements';

const env = environments.currentEnv;
const env = currentEnv;

const sequelize = new Sequelize(env.dbUrl, {
logging: false
});

const models = {
Test: sequelize.import('./test')
Test: sequelize.import('./test'),
User: sequelize.import('./user')
};

Object.keys(models).forEach((key) => {
Expand Down
36 changes: 36 additions & 0 deletions src/api/models/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const user = (sequelize, DataTypes) => {
const User = sequelize.define('user', {
firstName: {
type: DataTypes.STRING,
allowNull: true
},
lastName: {
type: DataTypes.STRING,
allowNull: true
},
userName: {
type: DataTypes.STRING,
allowNull: true
},
email: {
type: DataTypes.STRING,
allowNull: true
},
profileImage: {
type: DataTypes.STRING,
allowNull: true
},
provider: {
type: DataTypes.STRING,
allowNull: false
},
uniqueId: {
type: DataTypes.STRING,
allowNull: false
}
});

return User;
};

export default user;
15 changes: 15 additions & 0 deletions src/api/routes/passport/facebook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import express from 'express';
import { passport } from '../../../configs/environnements';
import socialLogin from '../../controllers/socialAuth';

// Declaring the app
const facebookRouter = express();

facebookRouter.get('/facebook', passport.authenticate('facebook'));
facebookRouter.get(
'/facebook/callback',
passport.authenticate('facebook'),
socialLogin.socialFacebookAuth
);

export default facebookRouter;
10 changes: 10 additions & 0 deletions src/api/routes/passport/google.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import express from 'express';
import { passport } from '../../../configs/environnements';
import socialLogin from '../../controllers/socialAuth';
// Declaring the app
const googleRouter = express();

googleRouter.get('/google', passport.authenticate('google', { scope: ['email', 'profile'] }));
googleRouter.get('/google/callback', passport.authenticate('google'), socialLogin.socialGoogleAuth);

export default googleRouter;
14 changes: 14 additions & 0 deletions src/api/routes/passport/twitter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import express from 'express';
import { passport } from '../../../configs/environnements';
import socialLogin from '../../controllers/socialAuth';
// Declaring the app
const twitterRouter = express();

twitterRouter.get('/twitter', passport.authenticate('twitter', { scope: ['email', 'profile'] }));
twitterRouter.get(
'/twitter/callback',
passport.authenticate('twitter'),
socialLogin.socialtwitterAuth
);

export default twitterRouter;
60 changes: 59 additions & 1 deletion src/configs/environnements.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import dotenv from 'dotenv';

import passport from 'passport';
import FacebookStrategy from 'passport-facebook';
import { OAuth2Strategy } from 'passport-google-oauth';
import TwitterStrategy from 'passport-twitter';

dotenv.config();

const port = process.env.PORT || 3000;
Expand Down Expand Up @@ -28,6 +33,59 @@ const environnements = [
}
];

const {
GclientId,
GclientSecret,
Gcallback,
FclientId,
FclientSecret,
Fcallback,
TclientId,
TclientSecret,
Tcallback
} = process.env;

passport.use(
new OAuth2Strategy(
{
clientID: GclientId,
clientSecret: GclientSecret,
callbackURL: Gcallback,
profileFields: ['name', 'photos', 'email']
},
(accessToken, refreshToken, profile, done) => done(null, profile)
)
);

passport.use(
new FacebookStrategy(
{
clientID: FclientId,
clientSecret: FclientSecret,
callbackURL: Fcallback,
profileFields: ['name', 'photos', 'email']
},
(accessToken, refreshTocken, profile, done) => done(null, profile)
)
);

passport.use(
new TwitterStrategy(
{
consumerKey: TclientId,
consumerSecret: TclientSecret,
callbackURL: Tcallback,
profile: ['name', 'photo', 'email']
},
(accessToken, refreshTocken, profile, done) => {
console.log(profile);
done(null, profile);
}
)
);

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

const currentEnv = environnements.find(el => el.name === env.toLocaleLowerCase());
export default { currentEnv, env };
export { currentEnv, env, passport };
24 changes: 18 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import express from 'express';
import '@babel/polyfill';
import passport from 'passport';
import session from 'express-session';
import dotenv from 'dotenv';
import apiRouter from './api/routes/index';
import docsRouter from './api/routes/docs';
import homeRouter from './api/routes/home';
import facebookRoutes from './api/routes/passport/facebook';
import googleRoutes from './api/routes/passport/google';
import twitterRoutes from './api/routes/passport/twitter';
import register from './middlewares/register.app';
import { sequelize } from './api/models/index';
import environnements from './configs/environnements';

import { currentEnv } from './configs/environnements';

const app = express();
const env = environnements.currentEnv;

const env = currentEnv;
dotenv.config();
const syncDbOnStart = env.name === 'test';

// session
app.use(
session({
saveUninitialized: true,
secret: process.env.secretOrKey
})
);
// Register middleware
register(app);

app.use(passport.initialize());
app.use('/api/', apiRouter);
app.use('/docs', docsRouter);

app.use('/', homeRouter);
app.use('/api/auth/', facebookRoutes, googleRoutes, twitterRoutes);

sequelize.sync().then(() => {
app.listen(env.port, () => {
Expand Down
Loading

0 comments on commit 9e77be6

Please sign in to comment.