Express passport.authenticate() not working properly - express

I'm having some issues with setting up passport. The information gets to the console.log(req.body) before passport.authenticate and then console.log(req.user) will return undefined afterwards. I will not hit the console.log inside of passport.use() function that is after the new LocalStrategy code. This does not though an error, nothing seems to happen. It will just enter the second if statement if(!user) and return me the status and error I outlined there. I have been trying to debug this for awhile and alas I'm no longer sure what the deal is.
this is what my auth file looks like
router.post("/login", (req, res, next) => {
console.log(req.body);
passport.authenticate("local", function (err, user, info) {
//console.log(req);
//console.log(user);
if (err) {
//console.log("cp1");
return res.status(400).json({ errors: err });
}
if (!user) {
return res.status(400).json({ errors: "No user found" });
}
req.logIn(user, function (err) {
console.log("cp1");
if (err) {
//console.log("cp3");
return res.status(400).json({ errors: err });
}
return res.status(200).json({ success: `logged in ${user.id}` });
});
})(req, res, next);
});
and this is what my passport.js file looks like
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(null, user);
});
});
passport.use(
new LocalStrategy((email, password, done) => {
console.log(`${email} , ${password}`);
db.User.findOne({ email: email })
.then((user) => {
if (!user) {
} else {
if (user.password === password) {
return done(null, user);
} else {
return done(null, false, { message: "Wrong Password" });
}
}
})
.catch((err) => {
return done(null, false, { message: err });
});
})
);
passport.initialize();
passport.session();

There is no such thing as req.user, I suppose you meant req.body.user or req.body.username depending on the JSON you send in the request.
I advice you to look at my repo below where I recently successfuly implemented Passport in Express:
https://github.com/fromb2b/saas

Related

`Cannot set headers after they are sent to the client ` when I try to login with `passport-google-oauth20`

When I tried to implement Google OAuth into my node app using passport-google-oauth20, I got a problem.
Whenever I attempt the first login to the secrets page with the following code, I fail to authenticate and got redirected to the /login page, also got the error saying Cannot set headers after they are sent to the client at the line serializing the user, even though newUser has been saved in the mongoDB.
However, I can successfully authenticate and login to the secrets page the second login attempt.
What's happening behind the scenes where the error occurs? How can I successfully authenticate the user when the first login attempt?
I referred to this Q&A as well.
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets"
},
(accessToken, refreshToken, profile, done) => {
User.findOne({ googleId: profile.id }, (err, foundUser) => {
if (err) return done(err);
if (!foundUser) {
const newUser = new User({
googleId: profile.id
});
newUser.save((err, savedUser) => {
if (err) throw err;
return done(null, savedUser);
});
}
return done(null, foundUser);
});
}
));
passport.serializeUser((user, done) => {
done(null, user.id); ///// The error occurs at this line /////
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get(
"/auth/google/secrets",
passport.authenticate("google", {
successRedirect: "/secrets",
failureRedirect: "/login"
})
);
app.get("/secrets", (req, res) => {
if (req.isAuthenticated()) return res.render("secrets");
res.redirect("/login");
});
The issue I see is within the verify callback. Calling return done(null, savedUser) will occur asynchronously. This means that the program will first call return done(null, foundUser) then after the saving call return done(null, savedUser).
To resolve the issue I would recommend refactoring the verify callback to use async/await. This makes it easier to reason about and reduces the chances of race conditions from conflicting callbacks.
Example Refactor:
async (accessToken, refreshToken, profile, done) => {
try {
let foundUser = await User.findOne({ googleId: profile.id });
if (!foundUser) {
const newUser = new User({
googleId: profile.id
});
await newUser.save();
return done(null, newUser);
}
return done(null, foundUser);
} catch (err) {
return done(err);
}
}));

Can someone please tell me where can i write my bcrypt-hashing function?

exports.postLogin = (req, res) => {
let { email, pass } = req.body;
console.log(email);
User.findOne({ email }, (err, result) => {
console.log(email, pass, result.pass);
if (err) {
res.json({ status: 'failed', message: err });
} else if (!result) {
res.json({ status: 'failed', message: 'email or password are wrong' });
} else {
bcrypt.compare(pass, result.pass).then(async (isPassCorrect) => {
if (isPassCorrect) {
const token = await signToken(result.id);
res.json({
status: 'success',
message: 'you logged in !!',
token,
});
} else res.json({ status: 'failed', message: 'email or password are wrong!' });
});
}
});
};
Your quetsion is not really clear about what you are trying to do, so I'm guessing into the black.
If I get you right, you are looking for the right place in order to hash a password before it gets saved, so you can use bcrypt.compare() on the encrypted password, is that right?
If yes, you could use mongooses pre-hook to hash the password before mongoose actually saves a document. To accomplish this add this to your model file
User.pre('save', async function (next) {
await bcrypt.genSalt(12).then(async salt => {
this.password = await bcrypt.hash(this.password, salt).catch(err => {
return next(err)
})
}).catch(err => {
return next(err)
})
})

after successfully register, i'm not able to login in express

after successful register with passport in express, when i try to login. it failed and i don't know which code is causing error. please help.
here is my code.
router.post('/register',function(req,res){
//fetch user info
var firstName=req.body.firstName,
lastName = req.body.lastName,
mobile= req.body.mobile,
email = req.body.email,
password = req.body.password,
newsConsent = req.body.newsConsent;
var userInfo = {firstName: firstName, lastName: lastName, mobile: mobile, email:email, newsConsent: newsConsent };
//register and create user
User.register(new User(userInfo), password, function(error, userCreated)
{
if (error)
{
console.log(error);
// req.flash("error", error.message);
return res.render("auth/register");
}
else
{
req.login(userCreated, function(err) {
if (err) {
console.log(err);
return next(err);
}
console.log(userCreated);
return res.redirect('/');
});
}
});
});
//login route
router.post("/login", passport.authenticate("local",
{
successRedirect: "/",
failureRedirect: "/register"
}), function(req, res){
console.log(req.body);
});
also please tell me how to know about the error in passport
You need declare your strategy, serialize and deserialize. Here's my code. You can edit it as you need. FYI, I was using 'nip_nim' instead of 'username', so I set "usernameField" as nip_nim. Here I also use 'flash' package to save my notification data.
passport.use(new LocalStrategy({
usernameField: 'nip_nim',
passReqToCallback: true
}, function (req, nip_nim, password, done) {
var params = {
nip_nim: nip_nim
}
var user = new User_Model(params);
user.getDataUserByNIPorNIM()
.then(function (result) {
if (!helper.isExist(nip_nim) || !helper.isExist(password)) {
return done(null, false, req.flash('message_err', 'NIM/NIM dan password tidak boleh kosong.'));
}
if (!result) {
return done(null, false, req.flash('message_err', 'NIP/NIM yang anda masukkan salah.'));
}
if (!bcrypt.compareSync(password, result.password)) {
return done(null, false, req.flash('message_err', 'Password yang anda masukkan salah.'));
}
return done(null, result);
})
}));
//serialize and deserialize passport
passport.deserializeUser(function (nip_nim, done) {
var params = {
nip_nim: nip_nim
}
var user = new User_Model(params);
user.getDataUserByNIPorNIM()
.then(function (result) {
done(null, result);
})
});
passport.serializeUser(function (req, user, done) {
done(null, user.nip_nim, req.flash('message_success', 'Welcome, ' + user.nama_unit_org + "."));
});
ok. i found the culprit. it's not passport, it's mongoose schema.
i have to add {index : true} in username.
`username : {type:String, unique: true, index: true},`.
after that everything works fine.

Express Passportjs Authenticate not being reached in router callback

If I pass passport.authenticate("local") as middleware into my route, it executes. But this way I do not have access to res so I can send a message back to my front end. However, if I attempt to call it in the route callback function, it is not firing.
router.post("/login", function(req, res, next) {
passport.authenticate("local", function(err, user, info) {
console.log("Unreached"); // This is not logging
});
})
Here is my passport.use inside app.js
passport.use(new LocalStrategy({
usernameField: "portalId"
}, function(portalId, enteredPassword, done) {
var params = {
TableName: "MyTableName",
KeyConditionExpression : "PortalID = :portalID",
ExpressionAttributeValues : {
":portalID" : Number(portalId)
}
}
docClient.query(params, function(err, user) {
if (err) throw err;
let realPassword = user.Items[0].password;
bcrypt.compare(enteredPassword, realPassword, function(err, res) {
if (err) throw err;
if (res) {
return done(null, user);
}
if (!res) {
return done(null, false, { message: "Invalid Credentials" });
}
})
})
}));
Saw in some other post a snippet of code using the custom callback and he had (req, res, next) right after the passport.authenticate function. I added this and my code was being fired now.

User in Passport Authentication Custom Callback is always false

I'm trying to use local authentication with Passport and Express, and I have two separate routes to log in: one for the website, which does a redirect, and one for the mobile app which I want to return a JSON object. The redirect route works. However, POSTing the same username and password to the other route receives the JSON response for a failed login. My LocalStrategy is as follows:
passport.use('local-signin', new LocalStrategy(
{passReqToCallback : true},
function(req, username, password, done) {
funct.localAuth(username, password)
.then(function (user) {
if (user) {
console.log("LOGGED IN AS: " + user.username);
req.session.success = 'You are successfully logged in ' + user.username + '!';
return done(null, user);
}
if (!user) {
console.log("COULD NOT LOG IN");
req.session.error = 'Could not log user in. Please try again.'; //inform user could not log them in
return done(null, false, { message: 'User not found' });
}
})
.fail(function (err){
console.log(err.body);
return done(err);
});
}
));
and these are the two places I use it:
app.post('/login', passport.authenticate('local-signin', {
successRedirect: '/',
failureRedirect: '/signin'
})
);
app.post('/api/login', function(req, res, next) {
passport.authenticate('local-signin', function(err, user, info) {
if (err) {
return res.json(user);
}
if (!user) {
return res.json(true);
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.json(user);
});
})
(req, res, next);
});
I get the success redirect from './login', but './api/login' replies with 'true' (the JSON response I have set for if 'user' is 'false'). This doesn't make any sense to me, but I can't find any problem with the code.
Any idea what the issue here could be? Thanks.