Im using passport.js (local strategy) to authenticate users but I am getting the following error:
Unhandled "error" event. (Incorrect arguments)
Detailed Error Message:
index.js file:
const {register: registerUser, login: loginUser} = require('../controllers/authentication');
// login
router
.route('/login')
.post(loginUser);
Authentication.js file:
// login function
let login = (req,res) => {
if(!req.body.email || !req.body.password){
sendJsonResponse(res, 400, {"message": "All fields required"});
return;
}
passport.authenticate('local', (err, user, info) => {
let token;
if(err){
sendJsonResponse(res, 404, err);
return;
}
if(user){
token = user.generateJwt();
sendJsonResponse(res, 200, {
"token": token
});
} else {
sendJsonResponse(res, 401, info);
}
})(req,res);
};
Passport.js File:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const User = mongoose.model('Users');
passport.use(new LocalStrategy({
usernameField: 'email',
}, function (email, password, done) {
User.findOne({'email': email}, function(err, user) {
if(err){
return done(err);
}
if(!user){
return done(null, false, {message: 'Incorrect Username.'});
}
if(!user.validPassword(password)){
return done(null, false, {message: 'Incorrect Password.'});
}
return done(null, user)
});
}
));
I can't seem to figure out what the issue might be. I've tried checking typeof for both email and password and they are indeed Strings. Does anybody know what could be the issue.
Related
This is my passport-config.js file. It should show the user can be serialised but for some reason it is not working.
const LocalStrategy = require('passport-local').Strategy
const { pool } = require("./db-config");
const bcrypt = require('bcrypt')
function initialize(passport, getUserById) {
const authenticateUser = async (email, password, done) => {
console.log(email, password);
pool.query(
`SELECT * FROM users WHERE email = $1;`,
[email],
(err, results) => {
if (err) {
throw err;
}
console.log(results.rows);
if (results.rows.length > 0) {
const user = results.rows[0];
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) {
console.log(err);
}
if (isMatch) {
return done(null, user);
} else {
//password is incorrect
return done(null, false, { message: "Password is incorrect" });
}
});
} else {
// No user
return done(null, false, {
message: "No user with that email address"
});
}
}
);
};
passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
return done(null, getUserById(id))
})
}
module.exports = initialize
I think it's something to do with the PSQL query and it not recognising the user id. Please help :)
I am currently implementing a login page via Node JS Express and Passport using Passport's local strategy: http://www.passportjs.org/packages/passport-local/.
The database is using MongoDB.
The problem that is occurring is I am unable to login successfully (sometimes I can, but it is not consistent) on an android phone and android tablet with User A.
The response being returned is a 401 (unauthorized error).
I have verified that I can log in successfully consistently with User A from a desktop computer, and also verified I can login on iOS devices (iPhone and iPad).
Does anyone have any suggestions, and / or know what the issue is?
Below is the code that executes the authentication
app_api/config/passport.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User');
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(username, password, done) {
User.findOne({ email: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, {
message: 'Incorrect username.'
});
}
if (!user.validPassword(password)) {
return done(null, false, {
message: 'Incorrect password.'
});
}
return done(null, user);
});
}
));
app_api/controllers/authentication.js
var passport = require('passport');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var sendJSONresponse = function(res, status, content) {
res.status(status);
res.json(content);
};
module.exports.test = function(req, res) {
sendJSONresponse(res, 200, { 'status' : 'success' });
};
module.exports.register = function(req, res) {
if(!req.body.name || !req.body.email || !req.body.password) {
sendJSONresponse(res, 400, {
"message": "All fields required"
});
return;
}
var user = new User();
user.name = req.body.name;
user.email = req.body.email;
user.setPassword(req.body.password);
user.setShowResume(false);
user.save(function(err) {
var token;
if (err) {
sendJSONresponse(res, 404, err);
} else {
token = user.generateJwt();
sendJSONresponse(res, 200, {
'token' : token
});
}
});
};
module.exports.login = function(req, res) {
if(!req.body.email || !req.body.password) {
sendJSONresponse(res, 400, {
'message': 'All fields required'
});
return;
}
passport.authenticate('local', function(err, user, info){
var token, showResume;
if (err) {
sendJSONresponse(res, 404, err);
return;
}
if(user){
token = user.generateJwt();
showResume = user.showResume;
sendJSONresponse(res, 200, {
'token' : token,
'showresume': showResume
});
} else {
sendJSONresponse(res, 401, info);
}
})(req, res);
};
module.exports.logout = function(req, res) {
req.logout();
res.redirect('/');
};
Below is the controller app_server/controllers/index.js and the function logincontinue which calls the app_api/controllers/authentication.js file and its function login:
app_server/controllers/index.js
var request = require('request');
var apiOptions = {
server : "http://localhost:3000"
};
if (process.env.NODE_ENV === 'production') {
apiOptions.server = "https://siteDomain.com";
}
module.exports.home = function(req, res) {
renderLoginPage(req, res);
};
/* Other routes / functions ... */
module.exports.logincontinue = function(req, res) {
var path = '/api/authentication/login', sess;
//var connectSid = res.req.cookies['connect.sid'];
var requestOptions = {
url : apiOptions.server + path,
method : "POST",
json : { email: req.body.username, password: req.body.password }/*,
headers : { 'set-cookie': connectSid }*/
};
request(requestOptions, function(err, response, body) {
if(err) {
renderPage(req, res, 'siteDomain.com', 'loginerror');
} else if(response.statusCode === 200) {
switch(body.showresume) {
case true:
res.render('loginsuccessresume', { title: 'siteDomain.com', page: 'loginsuccessresume', showresume: true });
break;
default:
renderPage(req, res, 'siteDomain.com', 'loginsuccess');
break;
}
} else if(response.statusCode === 401) {
res.render('loginunauthorized', { title: 'siteDomain.com', page: 'loginunauthorized', errormessage: body.message });
} else {
renderPage(req, res, 'siteDomain.com', 'loginerror');
}
});
};
var renderPage = function(req, res, titleValue, pageValue) {
res.render(pageValue, { title: titleValue, page: pageValue });
};
var renderLoginPage = function(req, res) {
res.render('index', { title: 'siteDomain.com', page: 'login' });
};
As an update, this issue has been resolved.
The issue was related to case-sensitivity with respect to the username field.
Changing req.body.username to req.body.username.toLowerCase() resolved the issue within app_server/controllers/index.js and the function logincontinue.
Thank you.
I'm trying to secure an API endpoint on a node.js express app that uses passport.
This is my route:
router.post('/api/devices', authController.isAuthorized, catchErrors(deviceController.getDevicesAPI));
This is my authorization method:
exports.isAuthorized = (req, res, next) => {
passport.authenticate('local', {session: false}, (err, user, info) => {
if (err || !user) {
return res.json({ message: 'Something is not right ', err, info });
}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(err);
}
next();
});
})(req, res);
};
From Postman or a separate local server, I get the response:
{
"message": "Something is not right ",
"err": null,
"info": {
"message": "Missing credentials"
}
}
This is the Postman configuration:
What am I missing?
How is your local strategy configured? It seems like a database query problem
As the sample in http://www.passportjs.org/docs/username-password/, please see my comments below
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) { //<--- Here is where you pass the UN&PASS
User.findOne({ username: username }, function(err, user) { //<--- Here is the sample code that should find you a user
if (err) { return done(err); } //<--- Here could be where the response is coming from
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user); //<--- Here is the sample code that should let you return that user
});
}
));
I finally dug it out from here. User.authenticate() is the method I was looking for.
exports.isAuthorized = async (req, res, next) => {
const username = req.body.username;
const password = req.body.password;
const user = await User.findOne({ email: username });
if (!user) {
res.sendStatus(403);
return;
}
user.authenticate(password, function(err, result) {
if (result) {
next();
return;
}
res.sendStatus(403);
});
};
I'm building an app in Node, using Passport and local signup and sign in strategies. I just keep running into an issue. All the required modules etc. are there. The following sign in routine works fine:
passport.use('local-signin', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('message', 'User not found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('message', 'Wrong password.'));
return done(null, user);
});
}));
However, the following sign up routine does not:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
console.log("signing up")
User.findOne({ 'local.email' : email }, function(err, user) {
if (err) {
return done(err);
} else if (user) {
return done(null, false, req.flash('message', 'That email address is already registered.'));
} else {
var newUser = new User();
}
// save the user
newUser.save(function(err) {
if (err) {
console.log("Error saving new user profile: " + err);
} else {
return done(null, newUser, req.flash('message', 'User account created'));
}
});
});
}))
Both routines are called within routes.js:
// POST : SIGNUP
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect: '/error',
failureFlash: true
}));
// POST : SIGNIN
app.post('/signin', passport.authenticate('local-signin', {
successRedirect: '/profile',
failureRedirect: '/',
failureFlash: true
}));
Any ideas where it might go wrong? As is, posting to /signup continuously results in a failureRedirect. My head is getting kinda sore from banging on the screen...
The only thing you need to change is:
if (!user.validPassword(password))
To
if (user.validPassword(password) === false)
I know, if (!user.validPassword(password)) is in examples on Passport.js official docs, but it is wrong.
I have just lost 2 hours of my life, figuring this out.
Use this code it will helps you to fix your problem
passport-authentication.js
var express=require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/user');//user is schema
var Verify = require('./verify');//verify is a file where the user is verified
/* GET users listing. */
router.get('/', Verify.verifyOrdinaryUser,function(req, res, next) {
User.find({},function(err,user){
if(err) throw err;
res.json(user);
});
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username,Email:req.body.Email}),
req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
if(req.body.firstname) {
user.firstname = req.body.firstname;
}
if(req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
verify.js
var User = require('../models/user');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
hope this helps for you...
I'm still a noob to node and webdev, but trying hard!
I get this error : can't set headers after they are sent
with the following while using passport.js and bcryptjs compare method for password validation on a mean stack
routes/login.js
var express = require('express')
var router = express.Router()
var mongoose = require('mongoose')
var User = mongoose.model('User')
var passport = require('passport')
router.post('/', function (req, res, next){
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).send(info)
}
})(req, res, next);
});
module.exports = router
authenticate/local.js
var passport = require('passport')
var LocalStrategy = require('passport-local').Strategy
var mongoose = require('mongoose')
var User = mongoose.model('User')
var bcrypt = require('bcryptjs')
passport.use(new LocalStrategy(function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
return done(err)
}
if (!user) {
return done(null, false, {
message: {
username: 'Incorrect username.'
}
})
}
bcrypt.compare(password, user.password, function(err, isMatch) {
if (err) {
return done(err)
}
if (!isMatch) {
return done(null, false, {
message: {
password: 'Incorrect password'
}
})
}
});
return done(null, user);
});
}));
This validates correctly for a valid username and password, and logs in.
For an invalid username, it correctly rejects the login attempt.
But for an invalid password, it logs in and then crashes the app with the Can't set headers error.
However if i change the bcrypt.compare to bcrypt.compareSync, then all validations are correct.
if (!bcrypt.compareSync(password, user.password)) {
return done(null, false, {
message: {
password: 'Incorrect password'
}
});
}
I would rather not depend on the sync methods, so help me please understand where I am going wrong!
bcrypt.compare() is async but you're calling done(null, user) immediately. Move it inside the callback and it should be fine:
bcrypt.compare(password, user.password, function(err, isMatch) {
if (err) { return done(err) }
if (!isMatch) {
return done(null, false, { message: { password: 'Incorrect password' } })
}
done(null, user)
})