I want to implement switch case for registration flow. Like normal sign up with
email, Phone number and password
with google
with facebook etc.
If user selects the continue with google button then switch to google registration and so on. How can I do that?
The controller file:
exports.register = catchAsync(async (req, res, error) => {
try {
const user = await userService.googleRegistration(req);
} catch (error) {
return res.failed(500, "Internal server error", error);
}
});
The userService file:
// GOOGLE REGISTRATION
exports.googleRegistration = async (req) => {
var google = require("googleapis").google;
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2();
oauth2Client.setCredentials({ access_token: req.params.access_token });
var oauth2 = google.oauth2({
auth: oauth2Client,
version: "v2",
});
oauth2.userinfo.get(async (err, res) => {
if (err) {
} else {
let user_data = new User({
first_name: res.data.given_name,
last_name: res.data.family_name,
});
let user = await user_data.save();
return user;
}
});
};
// NORMAL REGISTRATION
exports.register = async (user) => {
let new_user = new User({ ...user });
const user_data = await new_user.save();
const payload = { id: new_user._id };
user_data.JWToken = jwt.sign(payload, keys.JWToken, { expiresIn: 31556926 });
return user_data;
};
I recomended use an des-structuct object. NOT recomended use a switch it is bad for the memory and performance
const typeSingIn = {
facebook: function(){ /* function to join with fb */},
google: function() {/* your function to join with google*/},
// more options
}
app.post("/singIn", (req, res) => {
const {method} = req.body // expect the answer if the signIn is for fb, google or other method.
const singInType = typeSignIn[method]
try{
signInType() // this can be a promise if you want it
}catch(e){
res.json({status: 500, message: e})
}
})
Related
I'm using passport strategies for different socialMedia logins and getting the following two errors
InternalOAuthError: Failed to fetch user profile
Cannot set headers after they are sent to the client
I have doubt there somewhere I have returned a callback or response so getting 2nd error but for 1st don't know reasons scope seems to be correct!
strategy code
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_SECRET_KEY,
callbackURL: GOOGLE_CALLBACK_URL
}, async (acessToken, refreshToken, profile, done) => {
await User.findOne({ email: profile._json.email }, async (err, user) => {
if (err) {
console.log("passport.config --> err", err);
done(err, null);
} else if (user) {
if (user.socialType !== "GOOGLE" || user.socialType === null)
done(`LOGIN_CREDENTIALS_WITH_${(user.socialType || "PASSWORD").toUpperCase()}`, false);
else {
done(null, user);
}
} else {
// console.log(profile);
const user = {
email: profile._json.email,
socialId: profile.id,
socialType: "GOOGLE",
firstName: profile.name.givenName,
lastName: profile.name.familyName,
isActive: profile._json.email_verified,
isVerified: profile._json.email_verified,
socialImageUrl: profile._json.picture,
userType: "CUSTOMER"
};
const newUser = new User({ ...user });
const newUserData = await newUser.save();
done(null, newUserData);
}
});
}));
route code:
router.get('/auth/:socialType', customerCtrl.socialTypeLogin);
router.get('/auth/:socialType/callback', customerCtrl.socialTypeLoginCallback);
controller code:
const socialTypeLogin = async (req, res) => {
await customerService.socialTypeLogin(req, res);
};
const socialTypeLoginCallback = async (req,res) => {
await customerService.socialTypeLoginCallback(req,res);
};
service code:
const socialTypeLogin = async (req, res) => {
try {
const socialType = (req.params.socialType || '').toLowerCase();
const GOOGLE_SCOPE = ['email', 'profile'];
const FACEBOOK_SCOPE = ['email'];
let scope = [];
if (socialType === 'google') {
scope = GOOGLE_SCOPE;
} else if (socialType === 'facebook') {
scope = FACEBOOK_SCOPE;
}
let oauthOptions = { scope: scope};
const { returnUrl } = req.query;
if(returnUrl && returnUrl.trim().length !== 0) {
oauthOptions['state'] =JSON.stringify({ returnUrl: returnUrl });
}
passport.authenticate(socialType, oauthOptions)(req, res);
}
catch (error) {
}
}
/**
* #param {string} socialType
*/
const socialTypeLoginCallback = async (req, res) => {
const socialType = (req.params.socialType || '').toLowerCase();
// return new Promise((resolve, reject) => {
try {
passport.authenticate(socialType, async (err, user) => {
let webappRedirectURL = WEBAPP_LOGIN_URL;
try {
const state = req.query.state;
if(state) {
const stateObj = JSON.parse(state);
webappRedirectURL = stateObj.returnUrl;
}
} catch (err1) {
console.log("customer.service --> parsing error",err1);
}
if (err || !user) {
console.log("customer.service --> !user",err);
res.render('oauth-redirect', {
webappRedirectURL: webappRedirectURL,
success: false,
error: err,
timerCounter: 5,
accessToken: undefined
});
}
else {
console.log("customer.service --> Generating Token",user.generateJWT());
res.render('oauth-redirect', {
webappRedirectURL: webappRedirectURL,
success: true,
timerCounter: 5,
accessToken: user.generateJWT(),
error: undefined
});
}
})(req, res);
}
catch (error) {
console.log("customerService.js ==> socialTypeLoginCallback -->",error);
}
};
Thanks for help in advance!
I have doubt there somewhere I have returned a callback or response so getting 2nd error but for 1st don't know reasons scope seems to be correct!
In socialTypeLogin
add line
oauthOptions['session'] = false;
This is the error that I get:
"You have created a new client application that use…i/web/guides/gis-migration) for more information."
here are my codes on server, the statement inside console.log doesnt even show:
static async googleLogin(req, res, next) {
try {
console.log("masuk google login server")
const { id_token } = req.body
const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID)
const ticket = await client.verifyIdToken({
idToken: id_token,
audience: process.env.GOOGLE_CLIENT_ID
});
const payload = ticket.getPayload()
const email = payload.email
let password = email.toString().split('#')
password = password[0]
let user = await User.findOne({ where: { email } })
if (!user) {
let newUser = { email, password }
let createUser = await User.create(newUser)
const payload = {
id: createUser.id,
email: createUser.email
}
const access_token = generateToken(payload)
return res.status(201).json({ access_token })
} else {
const payload = {
id: user.id,
email: user.email
}
const access_token = generateToken(payload)
return res.status(200).json({ access_token })
}
} catch (err) {
console.log(err)
return next(err)
}
}
the console.log in my client also doesnt show
function onSignIn(googleUser) {
console.log("masuk client oauth")
$.ajax({
method: "POST",
url: `${baseUrl}/users/google-login`,
data: {
id_token: googleUser.getAuthResponse().id_token
}
})
.done((response) => {
console.log(response, "client response")
localStorage.setItem("access_token", response.access_token)
checkLocalStorage();
})
.fail((err) => {
console.log(err, "error client");
})
.always(() => {
authentication()
})
}
i tried deleting cache and run my app again, recreate a new project on google api (which genereated new ID). they didnt work
i cannot sign in to my app using existing google account. it loads when i clicked and asked me to wait a moment but then nothing happened.
my script.js
function onSignIn(googleUser) {
$.ajax({
url: `${baseUrl}/users/googlelogin`,
method: "POST",
data: {
access_token: googleUser.getAuthResponse().id_token,
googleToken: id_token
}
})
.done((response) => {
console.log(response, "ini response dr client")
localStorage.setItem("access_token", response.access_token)
authentication()
})
.fail((err) => {
console.log(err);
swal(
"Oops!", xhr.responseJSON.error[0], "error")
console.log(xhr.responseJSON.error[0])
})
}
my controller file:
static async googleLogin(req, res, next) {
try {
console.log("masuk google login")
const { id_token } = req.body
const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID)
const ticket = await client.verifyIdToken({
idToken: id_token,
audience: process.env.GOOGLE_CLIENT_ID
});
const payload = ticket.getPayload()
const email = payload.email
let password = email.toString().split('#')
password = password[0]
let user = await User.findOne({ where: { email } })
if (!user) {
let newUser = { email, password }
let createUser = await User.create(newUser)
const payload = {
id: createUser.id,
email: createUser.email
}
const access_token = generateToken(payload)
return res.status(201).json({ access_token })
} else {
const payload = {
id: user.id,
email: user.email
}
const access_token = generateToken(payload)
return res.status(200).json({ access_token })
}
} catch (err) {
console.log(err)
return next(err)
}
}
here are the error on console:
GET http://localhost:3000/todos 500 (Internal Server Error)
Uncaught {error: 'idpiframe_initialization_failed', details: 'You have created a new client application that use…i/web/guides/gis-migration) for more information.'}
i run my app on http://localhost:8080/client/
What I am trying to achieve is the following:
I have got a register screen in which the user enters his email and a password. When "register" ist pressed, I want the user to receive an email with a random 6-digit-code which allows him to enter this code on the next page which is the verification screen and with that verify the email.
Everything is set up, but I can only find ways via a generated verification link.
The way I would like to go is:
User enters credentials (email, password)
When pressed on "register" this data is saved to the database under the users collection with an ID and an email with the code is sent.
When this is done, the code can be entered and is somehow compared to the code that is saved somewhere in the database?? Because just sending the generated code to the next screen and store it in a class variable wouldn't be the best approach of achieving this I guess.
After success the users "verified" field is set to true in the database.
I don't really know the best way of programming this.
Please do not bother me for the naming of the routes ;) It's just like that for the moment for simplicity. Because of the same reason I only send response codes of 400 when something went wrong.
Flutter (registration screen)
child: RawMaterialButton(
onPressed: () async {
setState(() => isLoading = true);
if (email.length < 6) setState(() => isLoading = false);
else if (password.length < 6) setState(() => isLoading = false);
else {
var registerRes = await _auth.registerWithEmailAndPassword(email, password);
if (registerRes == 200) {
var code = randomNumeric(6);
var sendRes = await _auth.sendCode(email, code);
if (sendRes == 200) {
Routes.sailor.navigate(
'/confirmation',
params: {
'email': email,
'password': password,
'code': code
}
);
} else {
setState(() => isLoading = false);
}
} else {
setState(() => isLoading = false);
}
}
},
...
)
Flutter (Auth class)
import 'package:http/http.dart' as http;
import 'dart:convert';
class AuthService {
Future<String> loginWithEmailAndPassword(String email, String password) async {
Map data = {
'email': email,
'password': password
};
String body = json.encode(data);
var res = await http.post(
'http://10.0.2.2:3000/api/users/login',
headers: { 'Content-Type' : 'application/json'},
body: body
);
if (res.statusCode == 200) return res.body;
return null;
}
Future<int> registerWithEmailAndPassword(String email, String password) async {
Map data = {
'email' : email,
'password': password
};
String body = json.encode(data);
var res = await http.post(
'http://10.0.2.2:3000/api/users/register',
headers: { 'Content-Type' : 'application/json'},
body: body
);
return res.statusCode;
}
Future<int> sendCode(String email, String code) async {
Map data = {
'email' : email,
'code': code
};
String body = json.encode(data);
var res = await http.post(
'http://10.0.2.2:3000/api/users/send',
headers: { 'Content-Type' : 'application/json'},
body: body
);
return res.statusCode;
}
}
Node JS (auth.js)
const router = require('express').Router();
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { registerValidation, loginValidation } = require('../validation');
const User = require('../models/User');
const nodemailer = require('nodemailer');
router.post('/register', async (req, res) => {
const { error } = registerValidation(req.body);
if (error) return res.sendStatus(400);
const emailExists = await User.findOne({ email : req.body.email });
if (emailExists) return res.sendStatus(400);
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(req.body.password, salt);
const user = new User({
email : req.body.email,
password : hashedPassword
});
try {
const savedUser = await user.save();
} catch(err) {
res.sendStatus(400);
}
});
router.post('/send', async (req, res) => {
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL_ADDRESS,
pass: process.env.EMAIL_PASSWORD
},
tls: {
rejectUnauthorized: false
}
});
const mailOptions = {
from: '"coderave" <ccoderave#gmail.com>',
to: req.body.email,
subject: 'Bestätigungscode',
text: req.body.code
};
transporter.sendMail(mailOptions, function (err, info) {
if (err) res.sendStatus(400);
else res.sendStatus(200);
});
});
module.exports = router;
Kindly use the NPM Package (two-step-auth)
Use this package in your server index.js and create a route for it, and directly pass in the variables and you can do the rest,
In your app get the data from the form and pass it to your server and then to the package and it will return you an OTP to work with,
Kindly check the full procedures with the example here
Usage
const {Auth} = require('two-step-auth');
async function login(emailId){
const res = await Auth(emailId);
// You can follw the above approach, But we recommend you to follow the one below, as the mails will be treated as important
const res = await Auth(emailId, "Company Name");
console.log(res);
console.log(res.mail);
console.log(res.OTP);
console.log(res.success);
}
const app = express();
app.get('./auth/mailId/CompanyName', async(req, res)=>{
const {emailId} = req.params;
const data = login(emailId);
})
Output
This will help you a lot taking care of the process of verification under the HOOD.
So I have been trying to get Facebook authentication working. Locally, my code works perfectly. Once wrapped in Lambda using Claudia, the Facebook login seems to stop working. I have my login url authenticated in Facebook developer settings
var FB = require('fb');
FB.options({ version: 'v2.7' });
fb = new FB.Facebook({});
var bcrypt = require('bcryptjs');
var UserService = require('../services/user.service');
var config = require('../config');
var jwt = require('jsonwebtoken');
_this = this
exports.getFBLoginCredentials = async function (req, res, next) {
try {
let access_token = req.body.facebook_token;
FB.setAccessToken(access_token);
let facebookInfo = await new Promise(function (resolve, reject) {
FB.api('me/', { locale: 'en_US', fields: 'first_name, last_name, email' }, function (response) {
if (!response || response.error) {
reject(Error('Facebook Auth failed'));
}
resolve(response);
});
});
let user = await UserService.findUserByEmail(facebookInfo.email);
if (user) {
let updatedToken = await _createToken(user, 1);
let updatedRefreshToken = await _createToken(user, 7);
user.token = updatedToken;
user.refreshToken = updatedRefreshToken;
user.facebookToken = access_token;
user.emailVerified = true;
await UserService.updateUser(user);
return res.status(200).json({ status: 200, data: user, message: "Successfully Retrieved data" });;
}
let userFields = {
name: facebookInfo.first_name + ' ' + facebookInfo.last_name,
email: facebookInfo.email,
emailVerified: true,
facebook_token: access_token
}
let createdUser = await UserService.createUser(userFields);
return res.status(200).json({ status: 200, data: createdUser, message: "Successfully Retrieved data" });
}
catch (error) {
return res.status(400).json({ status: 400, message: error.message });
}
}
Figured it out. Turns out that the timeout of AWS Lambda was set to be 3.0 seconds but the call took longer than that.