Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/google authentication #6

Open
wants to merge 31 commits into
base: feature/signup
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
2bbb831
login
AwaleRohin May 15, 2019
ab2367e
some changes
AwaleRohin May 16, 2019
df798bc
feat: login
AwaleRohin May 22, 2019
e4d254d
fixes: code rendered
AwaleRohin May 23, 2019
efd1b2e
Route for google auth
vpul May 23, 2019
af9e5a8
fixes: code rendered
AwaleRohin May 23, 2019
f0ec63e
getinfo using promises
vpul May 23, 2019
317a5df
Merge branch 'feature/signup' of https://github.com/incwell-technolog…
AwaleRohin May 23, 2019
c5dd20e
wip
AwaleRohin May 24, 2019
055c5c5
cleaned up
vpul May 24, 2019
7b588a5
Created an external module for Access Token Generator
vpul May 24, 2019
d5a1937
Resolved merge conflict
vpul May 24, 2019
3ca1aff
Added googleapis to package.json
vpul May 24, 2019
5dc58ec
Added variables.env to .gitignore
vpul May 25, 2019
9b0b804
Removed variables.env
vpul May 25, 2019
c2b0fc7
Fixed typos
vpul May 25, 2019
cdb0fa1
fixes:error handler created
AwaleRohin May 26, 2019
b07fb91
Used http-status-code library for status code
vpul May 27, 2019
cb21707
Removed redundent try catch blocks
vpul May 27, 2019
39de10e
Save refresh token
vpul May 27, 2019
f2e0baf
added expiry time in schema for refresh token
vpul May 27, 2019
8f1e0bc
Used router() instead of app() in socialAuth.js
vpul May 27, 2019
ca5bfd9
Changed response to standard JSON response format
vpul May 27, 2019
7722f41
Moved all response logic to googleOauthHandler
vpul May 27, 2019
cbe46c2
Added API version to routes
vpul May 27, 2019
70b9981
authTokenGenerator now uses .env file instead of hard coded expiry time
vpul May 27, 2019
e713e22
feat:facebook signup
AwaleRohin May 27, 2019
1c69c15
bug:signup with email after facebook signup fixed
AwaleRohin May 28, 2019
f5c709c
Merged with Facebook Signup Controller
vpul May 28, 2019
dd1522b
Fixed merge conflict for User model
vpul May 28, 2019
a82fddc
google controller now pushes refresh token to the array instead of re…
vpul May 29, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ typings/

# dotenv environment variables file
.env
*.env
config/variables.env

# next.js build output
.next

secretKey.js

config
5 changes: 5 additions & 0 deletions config/secretKey.js.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports= {
token : {
key : 'keys'
},
}
35 changes: 28 additions & 7 deletions config/statusMsg.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,32 @@
module.exports= {
success : {
msg : "Success"
module.exports = {
success: {
msg: "true"
},
fail : {
msg : "Failure"
fail: {
msg: "false"
},
email :{
msg: 'A verification email has been sent to '
email: {
msg: "A verification email has been sent to "
},
token_exp: {
msg: "Token Expired"
},
no_user: {
msg: "User not found"
},
not_verified: {
msg: "User is not verified"
},
password_not_match: {
msg: "Invalid Password"
},
error: {
msg: "Some error"
},
email_verfied: {
msg: "Email already verified"
},
database_error: {
msg: "Database Error"
}
}
18 changes: 18 additions & 0 deletions controller/authTokenGenerator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const jwt = require('jsonwebtoken');
const secretKey = require('../config/secretKey');
const dotenv = require('dotenv')
dotenv.config({
path: './config/.env'
})

const access_token = async (email) => {
return await jwt.sign({ email }, secretKey.token.key, { expiresIn: process.env.access_token_exp });
};

const refresh_token = async (email) => {
return await jwt.sign({ email }, secretKey.token.key, { expiresIn: process.env.refresh_token_exp });
};

module.exports = {
access_token, refresh_token
};
6 changes: 4 additions & 2 deletions controller/emailVerify.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const nodemailer = require('nodemailer')
const path = require('path');
var EmailTemplate = require('email-templates');
exports.verifyEmail = async (email, host, token) => {
exports.verifyEmail = async (email, name, host, token) => {
let transporter = nodemailer.createTransport({
service: process.env.GMAIL_SERVICE,
port: process.env.PORT,
Expand All @@ -19,9 +19,11 @@ exports.verifyEmail = async (email, host, token) => {
emails.send({
template: path.join(__dirname, '..', 'email', 'mentors'),
message: {
to: email
to: email,
subject: "Account Verification"
},
locals: {
name: name,
host: host,
token: token
}
Expand Down
142 changes: 142 additions & 0 deletions controller/facebookContoller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
const dotenv = require('dotenv')
const request = require('request')
const User = require('../models/user')
const http = require('http-status-codes')
const statusMsg = require('../config/statusMsg')
const tokenGenerator = require('./authTokenGenerator')
const bcrypt = require('bcrypt')
const email_verify = require('./emailVerify')
const { validationResult } = require('express-validator/check')
const SALTING = 10
dotenv.config({
path: './config/.env'
})

exports.facebook = async (req, res, next) => {
try {
const fb_access_token = req.body.accessToken
await request(`https://graph.facebook.com/v3.3/me?fields=id,first_name,last_name,email&access_token=${fb_access_token}`,
async (err, response) => {
const userInfo = JSON.parse(response.body)
const access_token = await tokenGenerator.access_token(userInfo.email)
const refresh_token = await tokenGenerator.refresh_token(userInfo.email)
const payload = {
"accessToken": access_token,
"refreshToken": refresh_token,
"data": userInfo
}
try {
if (await dbQuery.idExists(userInfo, refresh_token)) {
return res.status(http.OK).json({
"success": statusMsg.success.msg,
"payload": payload
})
}
else if (await dbQuery.emailExists(userInfo)) {
await dbQuery.updateWithId(userInfo, refresh_token)
return res.status(http.OK).json({
"success": statusMsg.success.msg,
"payload": payload
})
}
else if (!userInfo.email) {
return res.status(http.CONFLICT).json({
"success": statusMsg.fail.msg,
"payload": userInfo
})
}
else {
await dbQuery.createAccount(userInfo, refresh_token)
return res.status(http.CREATED).json({
"success": statusMsg.success.msg,
"payload": payload
})
}
}
catch (err) {
err.status = http.INTERNAL_SERVER_ERROR
next(err)
}
}
)
}
catch (err) {
err.status = http.CONFLICT
next(err)
}
}

exports.reauthorize = async (req, res, next) => {
const errors = validationResult(req)
if (!errors.isEmpty()) {
return res.status(http.UNPROCESSABLE_ENTITY).json({
"success": statusMsg.fail.msg,
"payload": "",
"error": {
"code": http.UNPROCESSABLE_ENTITY,
"message": errors.array()
}
})
}
try {
let role = null
if (req.body.user_role == 1) { role = "Mentor" }
else { role = "Student" }
let hash = await bcrypt.hash(req.body.password, SALTING)
const access_token = await tokenGenerator.access_token(req.body.email)
const refresh_token = await tokenGenerator.refresh_token(req.body.email)
const user = new User({
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
user_role: role,
password: hash,
refresh_token: refresh_token
})
await user.save()
host = req.get('host')
await email_verify.verifyEmail(user.email, user.first_name, host, access_token)
const response = {
"accessToken": access_token,
"data": user,
"message": statusMsg.email.msg + user.email + '.'
}
res.status(http.CREATED).json({
"success": statusMsg.success.msg,
"payload": response
})
}
catch (err) {
err.status = http.CONFLICT
next(err)
}
}

const dbQuery = {
idExists: async (userInfo, refresh_token) => {
const facebookId = await User.findOne({ facebook_id: userInfo.id })
if (facebookId) {
await facebookId.refresh_token.push(refresh_token)
await facebookId.save()
}
return facebookId
},
emailExists: async (userInfo) => {
const facebookEmail = await User.findOne({ email: userInfo.email })
return facebookEmail
},
updateWithId: async (userInfo, refresh_token) => {
await User.findOneAndUpdate({ email: userInfo.email }, { facebook_id: userInfo.id, refresh_token: refresh_token })
},
createAccount: async (userInfo, refresh_token) => {
let user = {
first_name: userInfo.first_name,
last_name: userInfo.last_name,
email: userInfo.email,
facebook_id: userInfo.id,
verified_email: true,
refresh_token: refresh_token
}
await User.create(user)
}
}
106 changes: 106 additions & 0 deletions controller/googleController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
require('dotenv').config({
path: '../config/.env'
});

const httpStatus = require('http-status-codes');
const googleOAuth = require('../middleware/googleOauthClient');
const User = require('../models/user');
const tokenGenerator = require('./authTokenGenerator');
const statusMsg = require('../config/statusMsg')


module.exports.oauthHandler = async (req, res) => {
let googleAuthToken = req.body.accessToken;
try {
const response = await googleOAuth.getUserInfo(googleAuthToken);
const userInfo = response.data;

const access_token = await tokenGenerator.access_token(userInfo.email);
const refresh_token = await tokenGenerator.refresh_token(userInfo.email);

const payload = {
access_token,
refresh_token,
data: userInfo
};

try {
//If the google id already exists in the db, update refresh token in the db
if (await dbQuery.idExists(userInfo.id)) {
return res.status(httpStatus.OK).json({
"success": statusMsg.success.msg,
"payload": payload
});
//if the google email exists in the db, link the accounts
} else if (await dbQuery.emailExists(userInfo.email)) {
await dbQuery.updateWithId(userInfo, refresh_token);
return res.status(httpStatus.OK).json({
"success": statusMsg.success.msg,
"payload": payload
});
//otherwise, create a new account
} else {
await dbQuery.createAccount(userInfo, refresh_token);
return res.status(httpStatus.CREATED).json({
"success": statusMsg.success.msg,
"payload": payload
});
}
} catch(error) {
console.log(error);
return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({
"success": statusMsg.fail.msg,
"payload": {},
"error": {
"code": httpStatus.INTERNAL_SERVER_ERROR,
"message": statusMsg.database_error.msg
}
});
}
} catch(error) {
console.log(error);
return res.status(httpStatus.BAD_REQUEST).json({
"success": statusMsg.fail.msg,
"payload": {},
"error": {
"code": httpStatus.BAD_REQUEST,
"message": statusMsg.token_exp.msg
}
});
}
};



const dbQuery = {
idExists: async (id, refresh_token) => {
const googleId = await User.findOne({ google_id: id });
if (googleId) {
await googleId.refresh_token.push(refresh_token);
await googleId.save();
}
return googleId;
},
emailExists: async (email) => {
return await User.findOne({ email });
},
updateWithId: async (userInfo, refresh_token) => {
let google = await User.findOne({
email: userInfo.email
});
google.google_id = userInfo.id;
await google.refresh_token.push(refresh_token);
await google.save();
},
createAccount: async (userInfo, refresh_token) => {
let user = {
first_name: userInfo.given_name,
last_name : userInfo.family_name,
email: userInfo.email,
google_id: userInfo.id,
verified_email: true,
refresh_token
}
await User.create(user);
}
};
Loading