How to make signup function in nodejs using passportjs? - node.js

I am trying to make a signup and signin app in node.js. I am using passport.js for authentication purpose.
My main problem here is whenever i submit my signup form with valid form data, its automatically log user in. Other functions are working properly. Login works perfectly but whenever i submit signup form it submits without any errors and shows successful message too. But main drawback is along with singup it also log user in which i don`t want.
Here is my code
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
const validator = require('express-validator');
const passport = require('passport');
const expressHbs = require('express-handlebars');
const flash = require('connect-flash');
const session = require('express-session');
const mongoose = require('mongoose');
const configDB = require('./config/database.js');
//db configuration
mongoose.connect(configDB.url, (err) => {
if(err) {
console.log('Error connecting to databse');
} else {
console.log('Connection Successful');
}
});
require('./config/passport');
var index = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.engine('.hbs', expressHbs({defaultLayout: 'layout', extname: '.hbs'}));
app.set('view engine', '.hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(validator());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'node_modules')));
//required for passport
app.use(session({
secret: 'mysecret',
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use((req, res, next) => {
res.locals.login = req.isAuthenticated();
res.locals.session = req.session;
next();
});
app.use('/users', users);
app.use('/', index);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
passport.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/user');
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
passport.use('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, (req, email, password, done) => {
var fullname = req.body.name;
var address = req.body.address;
req.checkBody('name', 'Name is Required').notEmpty();
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty().isLength({ min: 4 });
var errors = req.validationErrors();
if (errors) {
var messages = [];
errors.forEach((error) => {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({ 'email': email }, (err, user) => {
if (err) {
return done(err);
}
if (user) {
return done(null, false, {message: 'That email is already taken.'});
} else {
var newUser = new User();
newUser.fullname = fullname;
newUser.email = email;
newUser.password = newUser.encryptPassword(password);
newUser.address = address;
newUser.isAdmin = false;
//saving the user
newUser.save((err) => {
if (err) {
return done(err);
}
return done(null, newUser, req.flash('info', 'Signup Completed, pleases login to continue'));
});
}
});
}));
passport.use('local-signin', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, (req, email, password, done) =>{
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Invalid password').notEmpty().isLength({ min: 4 });
var errors = req.validationErrors();
if (errors) {
var messages = [];
errors.forEach((error) => {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email': email}, (err, user) => {
if(err) {
return done(err);
}
if(!user) {
return done(null, false, {message: 'No User Found'});
}
if(!user.validPassword(password)) {
return done(null, false, {message: "Wrong Password"});
}
return done(null, user);
});
}));
user.js
var express = require('express');
var router = express.Router();
const passport = require('passport');
const User = require('../models/user');
/* GET users listing. */
router.get('/admin/dashboard', isLoggedIn, isAdmin, (req, res) => {
var user = req.user;
User.find({}, (err, users) => {
if(err) {
throw err;
} else {
res.render('admin/dashboard', {
successMsg: 'Hello' + ' ' + user.fullname,
users: users
});
}
});
});
//router.use('/', notLoggedIn, (req, res, next) => {
// next();
//});
router.get('/login', (req, res) => {
var messages = req.flash('error');
var infoMsg = req.flash('info');
res.render('users/login', { infoMsg: infoMsg, messages: messages, hasErrors: messages.length > 0 });
});
router.post('/login', passport.authenticate('local-signin', {// successRedirect: '/users/profile',
failureRedirect: '/users/login',
failureFlash: true
}), (req, res, next) => {
user = req.user;
role = user.isAdmin;
if(role) {
return res.redirect('/users/admin/dashboard');
} else {
return res.redirect('/users/profile');
}
});
router.get('/signup', (req, res, next) => {
var messages = req.flash('error');
res.render('users/signup', { messages: messages, hasErrors: messages.length > 0 });
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/users/login',
failureRedirect: '/users/signup',
failureFlash: true
}));
router.get('/profile', isLoggedIn, (req, res) => {
var user = req.user;
var role = user.isAdmin;
res.render('users/profile', {
user: user,
role: role,
successMsg: 'Welcome' + ' ' + user.fullname
});
});
router.get('/logout', isLoggedIn, (req, res, next) => {
req.logout();
res.redirect('/users/login');
});
//route middleware to make sure a use is logged in
function isLoggedIn(req, res, next) {
//if user is authenticated in the session, carry on
if(req.isAuthenticated()) {
return next();
}
res.redirect('/users/login');
}
function isAdmin(req, res, next) {
var user = req.user;
if(user.isAdmin == true) {
return next();
}
res.redirect('/users/profile');
}
function notLoggedIn(req, res, next) {
if(!req.isAuthenticated()) {
return next();
}
res.redirect('/');
}
module.exports = router;

You can use session configuration as per passport documentation
.post(passport.authenticate('local-signup', {
successRedirect: '/users/login',
failureRedirect: '/users/signup',
badRequestMessage: "You must fill in all of the form fields.",
failureFlash: true, // allow flash,
session: false // prevent auto-login
})
or you can give a callback to passport call and prevent session storing so it will not perform login
router.post('/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err, user) {
if (err) { return next(err) }
if (!user) { return res.redirect('/users/signup') }
res.redirect('/users/login');
})(req, res, next);
});

Related

I keep getting "Login sessions require session support" when I try to use tokens

So I am following a tutorial on how to use JSON tokens and I am getting an error, it was working fine using sessions but I can't figure out why I am having trouble, it is the exact code
this is my authenticate.js file:
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const User = require("./models/user");
const JwtStrategy = require("passport-jwt").Strategy;
const ExtractJwt = require("passport-jwt").ExtractJwt;
const jwt = require("jsonwebtoken"); // used to create, sign, and verify tokens
const config = require("./config.js");
exports.local = passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, { expiresIn: 3600 });
}; // config.secretKey is a string of random numbers
const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.secretKey;
exports.jwtPassport = passport.use(
new JwtStrategy(opts, (jwt_payload, done) => {
console.log("JWT payload:", jwt_payload);
User.findOne({ _id: jwt_payload._id }, (err, user) => {
if (err) {
return done(err, false);
} else if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
})
);
exports.verifyUser = passport.authenticate("jwt", { session: false });
This is my app.js file (the main file):
const createError = require("http-errors");
const express = require("express");
const path = require("path");
const logger = require("morgan");
const config = require("./config");
const indexRouter = require("./routes/index");
const usersRouter = require("./routes/users");
const mongoose = require("mongoose");
const passport = require("passport");
const url = config.mongoUrl;
const connect = mongoose.connect(url, {
useCreateIndex: true,
useFindAndModify: false,
useNewUrlParser: true,
useUnifiedTopology: true,
});
connect.then(
() => console.log("Connected correctly to server"),
(err) => console.log(err)
);
const app = express();
// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
// app.use(cookieParser("12345-67890-09876-54321"));
app.use(passport.initialize());
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use(express.static(path.join(__dirname, "public")));
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
this is the routes/users.js file (I believe the problem is here because I can sign-up (create new users) but I can't login with the same users)
const express = require("express");
const User = require("../models/user");
const passport = require("passport");
const authenticate = require("../authenticate");
const router = express.Router();
/* GET users listing. */
router.get(
"/",
function (req, res, next) {
res.send('send users')
}
);
router.post("/signup", (req, res) => {
User.register(
new User({ username: req.body.username }),
req.body.password,
(err, user) => {
if (err) {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.json({ err: err });
} else {
if (req.body.firstname) {
user.firstname = req.body.firstname;
}
if (req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save((err) => {
if (err) {
res.statusCode = 500;
res.setHeader("Content-Type", "application/json");
res.json({ err: err });
return;
}
passport.authenticate("local")(req, res, () => {
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({
success: true,
status: "Registration Successful!",
});
});
});
}
}
);
});
// I tried to add a console.log inside of the .post() route but it never reach it
router.post(
"/login",
passport.authenticate("local"),
(req, res) => {
const token = authenticate.getToken({ _id: req.user._id });
res.statusCode = 200;
res.setHeader("Content-Type", "application/json");
res.json({
success: true,
token: token,
status: "You are successfully logged in!",
});
}
);
router.get("/logout", (req, res, next) => {
if (req.session) {
req.session.destroy();
res.clearCookie("session-id");
res.redirect("/");
} else {
const err = new Error("You are not logged in!");
err.status = 401;
return next(err);
}
});
module.exports = router;
Basically, every time that i go to localhost:3000/users/login and send a POST request with the username and password, it tells me that I need to use express-session but I am trying to use tokens instead of session
The problem is caused when passport.authenticate('local') is called in routes/users.js file. It is a middleware that automatically calls req.login function in case correct username and password is provided.
The req.login() in turn, implements sessions in order to serialise the user in the session.
You can solve the issue by adding another parameter to passport.authenticate() as passport.authenticate('local', {session: false}. This ensures sessions are not implemented in the 'local' strategy and subsequently login can be performed.
Thanks, it helped me. You have to remove app.use(passort.session) from app.js and do
router.post('/login', passport.authenticate('local', { session: false }), (req, res) => {
var token = authenticate.getToken({ _id: req.user._id });
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.json({ success: true, token: token, status: 'You are successfully logged in!' });
});

Node.js passport not authenticating at login

I am trying to implement a simple user login and signup page for my application.
The signup page works and everything is getting stored in mongodb correctly. However, when I try to login it it does not seem to work. It is supposed to redirect to my root page but it will not do that. It always redirect back to /users/login
I've been going through a tutorial online so I do not understand why this isn't working. Here are the relevant files files.
user.js file
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
let User = require('../models/user');
// Load register form
router.get('/register', function(req, res) {
res.render('register', {
title : 'Register',
errors : req.flash('success')
});
});
// Submit register form
router.post('/register', function(req, res) {
// Get the fields from the form
const firstname = req.body.firstname;
const lastname = req.body.lastname;
const email = req.body.email;
const pass = req.body.pass;
const pass2 = req.body.pass2;
// Verify body is not empty.
req.checkBody('firstname', 'First name is required').notEmpty();
req.checkBody('lastname', 'Last name is required').notEmpty();
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('pass', 'Password is required').notEmpty();
req.checkBody('pass2', 'Passwords do not match.').equals(req.body.pass);
// Check for errors
let errors = req.validationErrors();
if (errors) {
res.render('register', {
errors:errors
});
} else {
// Create new user object
let newUser = new User({
firstname:firstname,
lastname:lastname,
email:email,
pass:pass
});
// Hash the password for security.
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(newUser.pass, salt, function(err, hash) {
if (err) {
console.log(err);
}
newUser.pass = hash;
newUser.save(function(err) {
if (err) {
console.log(err);
return;
} else {
console.log("Successful creation.")
req.flash('success', 'Account creation successful!');
res.redirect('/users/login');
}
});
});
})
}
});
// Load login form
router.get('/login', function(req, res){
res.render('login');
});
// Submit login form
router.post('/login', function(req, res, next) {
passport.authenticate('local', {
successRedirect: '..',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
module.exports = router;
passport.js file
const LocalStrategy = require('passport-local').Strategy;
const passport = require('passport');
const User = require('../models/user');
const config = require('../config/database');
const bcrypt = require('bcryptjs');
// User Authentication
module.exports = function(passport){
console.log("Made it intro str");
passport.use(new LocalStrategy(function(email, pass, done){
// Match username
let query = {email:email};
User.findOne(query, function(error, user){
if (error){
console.log("error");
return done(error);
}
if (!user) {
console.log("No user found");
return done(null, false, {message: 'No user found.'});
}
bcrypt.compare(pass, user.pass, function(error, isMatch) {
if (error) {
console.log("error2");
return done(error);
}
if (isMatch) {
console.log("Matching password");
return done(null, user);
} else {
console.log("Wrong password");
return done(null, false, {message: 'Invalid password.'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
App.js
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const logger = require('morgan');
const session = require('express-session');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const expressValidator = require('express-validator');
const config = require('./config/database');
const flash = require('connect-flash');
const passport = require('passport');
/* Connect to Database */
mongoose.connect(config.database, { useNewUrlParser: true });
let db = mongoose.connection;
// Check connection.
db.once('open', function(){
console.log('Connected to MongoDB.');
})
// Check DB error.
db.on('error', function(error){
console.log(error);
});
/* Initialize app */
var app = express();
/* Bring in models for database */
let User = require('./models/user');
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Load the view engines
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// Set public folder
app.use(express.static(path.join(__dirname, 'public')));
app.use(expressValidator());
// Keep users session
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}));
app.use(require('connect-flash')());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
// Express Validator Middleware
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
// Passport config
require('./config/passport')(passport);
app.use(passport.initialize());
app.use(passport.session());
// Load homepage
app.get('/', function(req, res) {
res.render('index', {
title: 'Index',
})
})
// Define routes
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/user');
app.use('/', indexRouter);
app.use('/users', usersRouter)
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
;
module.exports = app;
I believe the issue is in your passport.js file... By default, LocalStrategy expects to find credentials in parameters named username and password. You need to change that... something like so:
const localOptions = { usernameField: 'email', passwordField: 'pass' };
passport.use(new LocalStrategy(localOptions, function (email, pass, done) {
// Match username
let query = { email: email };
User.findOne(query, function (error, user) {
// etc etc...
});
}));
Link to the docs (at the bottom of the page...): http://www.passportjs.org/docs/username-password/

NodeJS POST Form always return 404

I've been running through a problem and I can not find out what it is. I am using Express for this.
I have an "addUser" form which has the following Pug form :
form(action='/adduser', method='POST')
and I have try POST method in the app.js that doesn't work :
app.post("/adduser", function (req, res, info, next){
console.log('This does not appear');
});
What I don't understand is why the following login POST method which is just right above the adduser works perfectly :
app.post("/login", passport.authenticate('local', {
// login things
});
NB : At the beginning, the /adduser was in a router and was also returning 404, that's why I tried to move it in app.js .
Feel free to ask any informations that you need.
Anthony.
FULL CODE
app.js:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var escape = require('escape-html');
var stock = require('./routes/stock');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// Variables pour le système d'users
var flash = require('connect-flash');
var crypto = require('crypto');
/* Login script */
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var connection = require('./lib/dbconn');
var sess = require('express-session');
var Store = require('express-session').Store;
var BetterMemoryStore = require(__dirname + '/memory');
var store = new BetterMemoryStore({expires: 60 * 60, debug: true});
app.use(sess({
name: 'StockInfo Sess.',
secret: 'C3ci3stUnSup3rS3cr3t',
store: store,
resave: true,
saveUninitialized: true
}));
//======================================================================================================================
// Configs =============================================================================================================
//======================================================================================================================
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use('/stock', stock);
//passport Strategy -- the express session middleware before calling passport.session()
passport.use('local', new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true //passback entire req to call back
}, function (req, username, password, done) {
if (!username || !password) {
return done(null, false, req.flash('message', 'All fields are required.'));
}
var escapeData = escape(username);
var comboPrenomNom = escapeData.split(".");
var prenom = comboPrenomNom[0].toLowerCase();
var nom = comboPrenomNom[1].toLowerCase();
connection.query("SELECT id, password, salt FROM users WHERE prenom = ? and nom = ?", [prenom, nom], function (err, rows) {
if (err) return done(req.flash('message', err));
if (!rows.length) {
return done(null, false, req.flash('message', 'Invalid username or password.'));
}
if (!(rows[0].password === crypto.createHash('sha256').update(rows[0].salt + escape(password)).digest('hex'))) {
return done(null, false, req.flash('message', 'Invalid username or password.'));
}
req.session.user = rows[0].id;
return done(null, rows[0].id);
});
}
));
passport.serializeUser(function (id, done) {
done(null, id);
});
passport.deserializeUser(function (id, done) {
connection.query("SELECT id, prenom, nom, hasChangedPass, rights FROM users WHERE id = " + id, function (err, rows) {
done(err, rows[0]);
});
});
//======================================================================================================================
// Routes ==============================================================================================================
//======================================================================================================================
app.get('/', function (req, res, next) {
res.redirect('/login');
});
app.get('/login', function (req, res) {
res.render('login/index', {
title: 'LogIn',
message: req.flash('message')
});
});
app.post("/login", passport.authenticate('local', {
successRedirect: '/stock',
failureRedirect: '/login',
failureFlash: true
}), function (req, res, info) {
res.render('login/index', {
'message': req.flash('message')
});
});
app.post("/adduser", function (req, res, info, next) {
if (req.body.prenom && req.body.nom && req.body.password) {
var prenom = escape(req.body.prenom).toLowerCase();
var nom = escape(req.body.nom).toLowerCase();
connection.query("SELECT * FROM users WHERE prenom = ? and nom = ?", [prenom, nom], function (err, rows) {
if (err) {
console.log(err);
}
if (!rows.length) {
var salt = generate_token(32);
var password = escape(req.body.password);
password = crypto.createHash('sha256').update(salt + '' + password).digest('hex');
connection.query("INSERT INTO users (prenom, nom, password, salt) VALUES (?, ?, ?, ?);", [prenom, nom, password, salt], function (err) {
if (err) {
console.log(err);
}
});
}
});
} else {
res.redirect('/stock/fromage');
}
});
app.get('/logout', function (req, res) {
req.session.destroy();
req.logout();
res.redirect('/login');
});
// 404
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error', {title: err.status});
});
function hasRights(req, res, next) {
if (req.user.rights[0] == 1 || req.user.rights[1] == 2 || req.user.rights[2] == 2 || req.user.rights[3] == 2) {
return next();
}
res.redirect('/stock');
}
function isAuthenticated(req, res, next) {
if (req.session.user) {
if (req.user.hasChangedPass) {
return next();
} else {
res.redirect('/stock/initpass');
}
}
res.redirect('/login');
}
module.exports = app;
/login/register.pug
extends ../layout
block content
include ../templates/header
.wrapper
form(action='/adduser', method='POST')
h3 Nouvel utilisateur
div.form-row
div.form-group
input.form-control(type='text', placeholder='Prénom', name='prenom' required)
div.form-row
div.form-group
input.form-control(type='text', placeholder='Nom', name='nom' required)
div.form-row
div.form-group
input.form-control(type='text', placeholder='Mot de Passe', name='password', value= pass required)
div.form-row
div.form-group
button.form-control Créer
div.form-row
div.form-group
p= rights
In your /adduser route you have 4 parameters in the callback function: (req, res, info, next). Remove info and Express will find your route.
With four parameters Express interprets your handler function as an error handler, see more information here: https://expressjs.com/en/guide/error-handling.html. Because of that you get a 404, as the request is passed through the middleware chain into the 404 handler.

Cast to ObjectId failed for value "586cc8b3ea780c071bbe2469" at path "_id" for model "User"

I saw a couple of post with similar to mine but I still getting the same error
here is my user schema
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var userSchema = mongoose.Schema({
local: {
email: String,
password: String,
},
});
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
module.exports = mongoose.model('User', userSchema);
my routes
var express = require('express');
var passport = require('passport');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/login', function(req, res, next) {
res.render('login.ejs', { message: req.flash('loginMessage') });
});
router.get('/signup', function(req, res) {
res.render('signup.ejs', { message: req.flash('loginMessage') });
});
router.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', { user: req.user });
});
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true,
}));
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true,
}));
module.exports = router;
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
my app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var flash = require('connect-flash');
var session = require('express-session');
var routes = require('./routes/index');
var users = require('./routes/users');
var configDB = require('./config/database.js');
mongoose.connect(configDB.url);
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({ secret: 'shhsecret' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
require('./config/passport')(passport);
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
And here is my passport.js Im using local passport
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
module.exports = function(passport) {
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('local-signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true,
},
function(req, email, password, done) {
process.nextTick(function() {
User.findOne({ 'local.email': email }, function(err, user) {
if (err)
return done(err);
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already in use.'));
} else {
var newUser = new User();
newUser.local.email = email;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: 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('loginMessage', 'No user found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Wrong password.'));
return done(null, user);
});
}));
};
passport works it save the user to the database
expressauth 5 > db.users.find()
{ "_id" : ObjectId("586cc8b3ea780c071bbe2469"), "local" : { "password" : "$2a$08$vANw7GJIk8RUVEpJWnwSpOVQ77RuHCjbXiGoQVl.Fx/thhbMkEVWu", "email" : "david#david.com" }, "__v" : 0 }
expressauth 6 >
Cast to ObjectId failed for value “586cc8b3ea780c071bbe2469” at path “_id” for model “User”
I have built a couple apps that use passport oauth the exact same way that I have displayed above. So I dont know why Im getting this error.
Any suggestions?
I had the same problem with mongoose version > 4.7.2
Problem is about bson package.
I solved it with installing an older version of mongoose.
npm install mongoose#4.7.2
or you can change package.json to use exact version 4.7.2 "mongoose": "4.7.2"
You can update to newer versions after the problem is solved. You can track it on here.
The error exists in your serializeUser function in passport.
You need to use user._id instead of user.id.
since there is no field as id in your UserSchema, user.id will beundefined, and while deserializing the user, undefined is not typeOf ObjectId, thus it is throwing above error.
Try this:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
Update:
Do this in your deserializeUser:
cast the upcoming id to ObjectId, just to be sure, and then use that ID to query the User.
var userId = mongoose.Schema.Types.ObjectId(id);
User.findById(userId , function(err, user) {
done(err, user);
});
Dont forget to include mongoose in the same file.
var mongoose=require('mongoose');
Hopefully this will help you.
This is due to latest version of mongoose, you have to use findOneAndRemove instead of FindByIdAndRemove.
That is cast objectId problem.

Can't send headers after they are sent

I am new to nodejs. I have been trying to create a simple login and register system using mongodb and express. I have created the entire app but with one error:
var express = require('express')
, passport = require('passport')
, util = require('util')
, LocalStrategy = require('passport-local').Strategy;
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
//var flash = require('connect-flash');
var monk = require('monk');
var db = monk('localhost:27017/loginsystem');
var collection = db.get('messagescollection');
function findById(id, fn) {
var collection = db.get('messagescollection');
collection.findOne({ _id: id }).on('success', function (doc) {
fn(null, doc);
});
}
function findByUsername(username, fn) {
collection.findOne({ username: username }).on('success', function(doc) {
return fn(null, doc);
});
return fn(null, null);
}
var app = express();
app.use(bodyParser.json()); // for parsing application/json
app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded
app.use(function(req,res,next){
req.db = db;
next();
});
app.use(cookieParser());
app.use(session({
secret: 'keyboard cat'
hours
}));
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
console.log("user",user);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
console.log(id,"id");
findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(
function(username, password, done) {
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
}
));
app.use(express.static(__dirname + '/public'));
app.get('/account', ensureAuthenticated, function(req, res){
res.send(req.user);
});
app.get('/login', function(req, res){
res.redirect("/login.html") //redirect back to homepage
});
app.get('/register', function(req, res) {
res.redirect("/register.html") //redirect back to homepage
})
app.post('/login', passport.authenticate('local', { failureRedirect: '/login'}), function(req, res) {
console.log("success",req.user);
res.redirect('/account');
});
app.post('/register', function(req, res) {
console.log(req.body);
// Submit to the DB
collection.insert({
"username" : req.body.username,
"email" : req.body.email,
"password" : req.body.password
}, function (err, doc) {
if (err) {
// If it failed, return error
res.send("There was a problem adding the information to the database.");
}
else {
//res.redirect('/account');
}
});
});
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
app.listen(9000);
function ensureAuthenticated(req, res, next) {
console.log("req.user",req.user,req.session);
if (req.isAuthenticated()) { return next(); }
res.redirect('/login');
}
When I register, the user is added to the database. And it is redirected to /login but when I login then I get this error:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/express/lib/response.js:700:10)
at ServerResponse.res.location (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/express/lib/response.js:814:8)
at ServerResponse.redirect (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/express/lib/response.js:853:8)
at /home/mareebsiddiqui/SummerOfCode/loginsystem/app.js:130:7
at Layer.handle [as handle_request] (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/express/lib/router/layer.js:82:5)
at next (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/express/lib/router/route.js:110:13)
at complete (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/passport/lib/middleware/authenticate.js:243:13)
at /home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/passport/lib/middleware/authenticate.js:250:15
at pass (/home/mareebsiddiqui/SummerOfCode/loginsystem/node_modules/passport/lib/authenticator.js:427:14)
How could I resolve this issue? Thanks.
EDIT: I know that there are many questions with the same title but there problems are different. This error is caused by many different situations and my situation is different from others. I have a problem of redirects whereas other questions have problems of ending a response.
You should use return response.<method>. For example, return response.redirect().
Also, response.end() might be helpful.

Resources