I'm new at Node.js and really a newbie at MongoDB.
I'm trying to make an authentication system using Google OAuth 2.0 and passport.
I keep getting this error:
Error: User validation failed: lastName: Path `lastName` is required.
Can you help me? I got this code from GitHub and I'm trying to modify it, but this error doesn't let me continue my project.
This is the problematic code:
const mongoose = require('mongoose')
const User = require('../models/User')
module.exports = function (passport) {
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: '/auth/google/callback',
},
async (accessToken, refreshToken, profile, done) => {
const newUser = {
googleId: profile.id,
displayName: profile.displayName,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
image: profile.photos[0].value,
}
try {
let user = await User.findOne({ googleId: profile.id })
if (user) {
done(null, user)
} else {
user = await User.create(newUser)
done(null, user)
}
} catch (err) {
console.error(err)
}
}
)
)
passport.serializeUser((user, done) => {
done(null, user.id)
})
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => done(err, user))
})
}
Related
I'm using passportJs Google Authetication. Although a user exist in database, When I login the system with this user, It creates this user again in the database as a new user. How can I fix this problem, can you help ?
Thats image of the database:
Here is my codes:
module.exports = passport.use(
new GoogleStrategy(
{
clientID: config.google.clientID,
clientSecret: config.google.clientKey,
callbackURL: "/auth/google/callback",
},
async (accessToken, refreshToken, profile, done) => {
try {
const user = await models.User.findOne({ google: { id: profile.id } });
if (user) {
done(null, user);
} else {
const newUser = new models.User({
google: profile,
isSocialAuth: true,
name: profile.name.givenName,
lastName: profile.name.familyName,
cart: { items: [] },
});
await newUser.save();
done(null, newUser);
}
} catch (error) {
done(error, null);
}
}
)
);
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
models.User.findById(id, (err, user) => done(err, user));
});
My Router:
router.get("/auth/google", passport.authenticate("google", { scope: ["profile"] }));
router.get("/auth/google/callback", passport.authenticate("google", { failureRedirect: "/login" }), async (req, res) => {
req.session.user = req.user;
req.session.isAuthenticated = true;
res.redirect("/");
});
module.exports = router;
My UserSession Middleware:
module.exports = (req, res, next) => {
if (!req.session.user) {
return next();
}
models.User.findById(req.session.user._id)
.then((user) => {
req.user = user;
next();
})
.catch((err) => {
console.log(err);
});
};
After signing in, in the Passport part,
the findOne query might have some issue. It is not able to find the user & hence it is registering again.
Replace
const user = await models.User.findOne({ google: { id: profile.id } });
to
const user = await models.User.findOne({ "google.id": profile.id });
& check if it works.
I am trying to sign up my users using facebook using passportjs. I am using mongodb as database and using mongoose to interact with it.
const userSchema = mongoose.Schema({
email: String,
password: String,
googleId: String,
facebookId: String,
secret: [String],
});
const User = mongoose.model("users", userSchema);
This is the schema.
passport.use(new FacebookStrategy({
clientID: process.env.APP_ID,
clientSecret: process.env.APP_SECRET,
callbackURL: process.env.CALLBACK_URL,
profileFields: ['id', 'displayName', 'photos', 'email']
},
function (accessToken, refreshToken, profile, done) {
//check user table for anyone with a facebook ID of profile.id
console.log(profile);
User.findOne({
facebookId: profile.id
}, function (err, user) {
if (err) {
return done(err);
}
//No user was found... so create a new user with values from Facebook (all the profile. stuff)
if (!user) {
user = new User({
name: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'facebook',
User.findOne({'facebook.id': profile.id } will match because of this next line
facebook: profile._json
});
user.save(function (err) {
if (err) console.log(err);
return done(err, user);
});
} else {
//found user. Return
return done(err, user);
}
});
}
));
This is the code of facebook strategy. I can sign up succesfully using facebook but I am not able to add the user to my database. I have the same code for my google oauth and it seems to work in google.
i have simple passport-facebook & google oauth application and it works but problem it is not serializing users properly i guess because when i log req.user it returns undefined. here is my code for facebook oauth
passport.serializeUser((user,done)=>{
done(null,user.id)
})
passport.deserializeUser((id,done)=>{
const user = User.findById(id)
done(null, user)
})
passport.use(new FacebookStrategy({
clientID: process.env.FB_CLIENT_ID,
clientSecret: process.env.FB_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/facebook/callback"
},
async (accessToken, refreshToken, profile, done) => {
const user = await User.findOne({ userId: profile.id })
if(user){
console.log('existing user '+ user)
return done(null,user)
}else{
const newuser = User.create({ username: profile.displayName,userId: profile.id });
console.log(newuser.toString())
done(null,newuser)
}
}))
and here is passport-google-oauth2
passport.serializeUser((user,done)=>{
done(null,user.id)
})
passport.deserializeUser((id,done)=>{
const user = User.findById(id)
done(null, user)
})
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/callback"
},
async (accessToken, refreshToken, profile, done) => {
const user =await User.findOne({ userId: profile.id })
if(user){
console.log('existing user '+ user )
return done(null,user)
}else{
const newuser = User.create({ username: profile.displayName,userId:
profile.id });
console.log(newuser)
done(null,newuser)
}
}))
and here is route config
router.get('/facebook', passportFacebook.authenticate('facebook'));
router.get('/facebook/callback',passportFacebook.authenticate('facebook', { failureRedirect: '/auth/login' }),
function(req, res) {
res.redirect('/');
});
router.get('/google',
passportGoogle.authenticate('google', { scope: 'profile' }));
router.get('/google/callback',passportGoogle.authenticate('google', {
failureRedirect: '/auth/login' }),
function(req, res) {
res.redirect('/');
});
so what is wrong with this code?
The problem is you don't await for user in deserializeUser.
const user = User.findById(id)
You need to use then or await result from User.findById. So your deserializeUser code should be
passport.deserializeUser(async (id,done) => {
const user = await User.findById(id)
done(null, user)
})
In passport-facebook Strategy, when I query using Mongoose User.findOne() it doesn't return error or success object. Nodejs when come to this block, escape this block User.findOne(){...} without giving any error and success i.e.silently escape.
passport.use(new FacebookStrategy({
clientID: config.get('facebook.clientID'),
clientSecret: config.get('facebook.clientSecret'),
callbackURL: config.get('facebook.callbackURL'),
passReqToCallback: true,
profileFields: ['id', 'email', 'first_name', 'last_name']
},
function(req, accessToken, refreshToken, profile, done) {
// check if the user is already logged in
let fbInfo = profile._json;
// console.log(fbInfo);
if (!req.user) {
User.findOne({ 'email': fbInfo.email }, function(err, user) {
if (err)
return done(err);
if (user) {
I think you don't make it inside the if statement.
Change if (!req.user) to if (req.user) and it should work.
--
However here is some sample code using Passport Facebook authentication strategy:
passport.use(new FacebookStrategy({
clientID: oauth.facebook.clientID,
clientSecret: oauth.facebook.clientSecret,
callbackURL: oauth.facebook.callbackURL,
// passReqToCallback: true,
profileFields: ['id', 'emails', 'name']
},
function (accessToken, refreshToken, profile, done) {
process.nextTick(function () {
User.findOne({
$or: [
{ 'facebook.id': profile.id },
{ 'email': profile.emails[0].value }
]
}, function (err, user) {
if (err) {
return done(err)
}
if (user) {
if (user.facebook.id == undefined) {
user.facebook.id = profile.id
user.facebook.token = accessToken
user.facebook.email = profile.emails[0].value
user.facebook.name = profile.name.givenName + ' ' + profile.name.familyName
user.save()
}
return done(null, user)
} else {
let newUser = new User()
...
newUser.save(err => {
if (err) {
console.log(err)
throw err
}
return done(null, newUser)
})
}
})
})
}
))
I am trying to build a login system with Facebook, Google and local passport, I am using Node.js, passport.js, and ORM to finish it, but I faced one problem now, my user model is like below
const User = connection.define('user', { googleID: {
type: Sequelize.STRING, }, facebookID: {
type: Sequelize.STRING, }, firstname: {
type: Sequelize.STRING,
notEmpty: true,
},
lastname: {
type: Sequelize.STRING,
notEmpty: true,
},
username: {
type: Sequelize.TEXT,
},
email: {
type: Sequelize.STRING,
validate: {
isEmail: true,
},
},
password: {
type: Sequelize.STRING,
allowNull: false,
},
last_login: {
type: Sequelize.DATE,
}, });
After this setting, whenever I want to log on my website through Facebook, it kept showing SEQUELIZE ERROR, password required! I know it the reason is I don't have password while signing in with Facebook, but what can I do with this issue? I saw this page on GitHub https://github.com/feathersjs/authentication/issues/168
but I still have no clue in using this feathers-joi tool, can anyone give me some advice? Thank you
Here is my Facebook.js code
const passport = require('passport');
const cookieSession = require('cookie-session');
const FacebookStrategy = require('passport-facebook').Strategy;
const User = require('../models/User');
const keys = require('../secret/keys.js');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id).then(user => {
done(null, user);
});
});
passport.use(new FacebookStrategy({
clientID: keys.facebookClientID,
clientSecret: keys.facebookClientSecret,
callbackURL: '/auth/facebook/callback',
}, (accessToken, refreshToken, profile, done) => {
User.findOne({ where: { facebookID: profile.id } }).then(existinguser => {
if (existinguser) {
//Nothing will happen, the ID already exists
done(null, existinguser);
}else {
User.create({ facebookID: profile.id }).then(user => done(null, user));
}
});
}));
My passport.js would be like below(Still need some fix)
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport, user) {
var User = user;
var LocalStrategy = require('passport-local').Strategy;
passport.use('local-signup', new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
var generateHash = function(password) {
return bCrypt.hashSync(password, bCrypt.genSaltSync(8), null);
};
User.findOne({
where: {
email: email
}
}).then(function(user) {
if (user)
{
return done(null, false, {
message: 'That email is already taken'
});
} else
{
var userPassword = generateHash(password);
var data =
{
email: email,
password: userPassword,
firstname: req.body.firstname,
lastname: req.body.lastname
};
User.create(data).then(function(newUser, created) {
if (!newUser) {
return done(null, false);
}
if (newUser) {
return done(null, newUser);
}
});
}
});
}
));
}
try this
passport.use(new FacebookStrategy({
clientID: keys.facebookClientID,
clientSecret: keys.facebookClientSecret,
callbackURL: '/auth/facebook/callback',
}, (accessToken, refreshToken, profile, done) => {
User.findOne({ where: { facebookID: profile.id } }).then(existinguser => {
if (existinguser) {
//Nothing will happen, the ID already exists
done(null, existinguser);
}else {
var object = {
facebookID: profile.id,
password: ""
}
User.create(object).then(user => done(null, user));
}
});
}));