I have made a simple Node app using authentication. I am able to signup using the form but I am not able to login using the login form.
I have written the code below. Using this I can register using the signup route, but I am not able to log in. Also, I am not getting any error, I am just redirected to failure redirect path.
Here is the code I have written
var express = require('express'),
app = express(),
bodyParser = require('body-parser'),
mongoose = require('mongoose'),
User = require("./views/models/user"),
passport = require('passport'),
flash = require('connect-flash'),
morgan = require('morgan'),
cookieParser = require('cookie-parser'),
session = require('express-session'),
expressValidator = require('express-validator'),
LocalStrategy = require('passport-local').Strategy;
mongoose.connect("mongodb://localhost/travelogue");
// set up our express application
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
// required for passport
app.use(bodyParser.urlencoded({extended :true}));
app.use(bodyParser.json());
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
app.use(require('express-session')({
secret : "Adish",
resave : false,
saveUninitialized : false,
}));
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.use(express.static('public'));
app.set("view engine","ejs");
//routes
app.get("/Login",function(req,res){
res.render("login");
});
app.get("/Signup",function(req,res){
res.render("signup");
});
app.get("/",function(req,res){
res.render("index");
});
// we will use route middleware to verify this (the isLoggedIn
function)
/*app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user // get the user out of session and pass to
template
});
});*/
app.get("/logout",function(req,res){
req.logout();
res.redirect("/");
});
// Express Validator
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
};
}
}));
// process the signup form
app.post('/Signup', function(req, res){
var firstname = req.body.firstname;
var lastname = req.body.lastname;
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var gender = req.body.gender;
// Validation
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('username', 'Username is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
var errors = req.validationErrors();
if(errors){
res.render('signup',{
errors:errors
});
} else {
var newUser = new User({
firstname: firstname,
lastname : lastname,
username : username,
email : email,
password : password,
gender : gender
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
req.flash('success_msg', 'You are registered and can now
login');
res.redirect('/login');
}
});
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(username, password, done) {
User.findOne({ username: 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.post('/login', passport.authenticate('local', {
successRedirect : '/profile', // redirect to the secure profile
section
failureRedirect : '/login', // redirect back to the signup page
if there is an error
failureFlash : true // allow flash messages
}));
app.get('/profile',function(req,res){
res.render('profile.ejs');
});
app.listen(process.env.PORT,process.env.IP,function(){
console.log("Server is running !");
});
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
This is the userSchema used to register (user.js):
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
// User Schema
var UserSchema = mongoose.Schema({
firstname : String,
lastname : String,
username : {type :String, unique : true},
email : String,
password : String,
gender : String,
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
if(err)
console.log(err);
});
});
};
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
};
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
};
module.exports.comparePassword = function(candidatePassword, hash,
callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
};
Related
users.js
technologies used
passport
passport-local
bcryptjs
multer for the profile picture upload
here's the code for the register,log in and the authentication
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: './uploads'});
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register', function(req, res, next) {
res.render('register',{title:'Register'});
});
router.get('/login', function(req, res, next) {
res.render('login',{title:'Login'});
});
router.post('/login',
passport.authenticate('local', {failureRedirect: '/users/login', failureFlash: 'Invalid username or password'}),
function(req, res) {
req.flash('success', 'You are now logged in');
res.redirect('/');
});
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
User.getUserById(id, function(err, user){
done(err, user);
});
});
passport.use(new LocalStrategy(function (username, password, done) {
User.getUserByUsername(username, function (err, user) {
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown user'});
}
User.comparePassword(password, user.password, function(err,isMatch){
if(err) return done (err);
if(isMatch){
return done(null, user);
}else {
return done(null, false, {message: 'Invalid Password'});
}
});
});
}));
router.post('/register', upload.single('profilepicture'), function(req, res, next) {
var name = req.body.name;
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var password2 = req.body.password2;
var profile = req.body.profilepicture;
if(req.file){
console.log('uploading...');
}
else{
console.log('not uploaded');
var profilepicture = 'noimage.jpg';
}
//form validator
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email is not valid').isEmail();
req.checkBody('username','Username required').notEmpty();
req.checkBody('password','Password cannot be empty').notEmpty();
req.checkBody('password2','Passwords do not match').equals(req.body.password);
//check errors
var errors = req.validationErrors();
if(errors){
res.render('register', {
errors:errors
});
}
else{
//var User = module.exports = mongoose.model('User', userSchema);
var newUser = new User({
name:name,
email:email,
username: username,
password:password,
profilepicture:profilepicture
});
User.createUser(newUser,function(err,user){
if(err) throw err;
console.log(user);
});
req.flash('success', 'You are now registered and can log in');
res.location('/');
res.redirect('login');
}
});
router.get('/logout', function (req,res){
req.logout();
req.flash('success', 'You are now logged out');
res.redirect('/users/login');
});
module.exports = router;
the user can register successfully and the data gets stored in the database, the password is also hashed but during log in, the text 'Invalid username or password' keeps being displayed.there is no error being displayed just that the user cannot be able to log in even after registering.
what might be the issue?
I guess the code User.comparePassword(password, user.password, function(err,isMatch){ is comparing plain text password with the encrypted password from the db. Could you please check if both password and user.password are encrypted.
Well you compare your plain password with a plain password in the database. Why should you use .comparePassword() if you could just check it with password === user.password?
The problem is that you store your password as a plain text in your database. You need to hash it first and you can do it with bcrypt
Here replace this with your else block:
else {
// hash the password
let salt = 12;
bcrypt.hash(password, salt, function(err, hash) {
if (err) return res.status(500).json(err);
//var User = module.exports = mongoose.model('User', userSchema);
var newUser = new User({
name: name,
email: email,
username: username,
password: hash,
profilepicture: profilepicture
});
User.createUser(newUser, function(err, user) {
if (err) throw err;
console.log(user);
});
req.flash("success", "You are now registered and can log in");
res.location("/");
res.redirect("login");
});
}
What your compare function do is:
It hashes your plain text password with the salt value thats saved in the hash that you compare. And then it checks if both hashes are the same.
I am new to building REST API's, and I am trying to enter new user information into a collection called 'Users', however, when I submit the information I get Cannot POST /register
Below is my code
server.js
require('dotenv').config()
const express = require('express')
const app = express()
const mongoose = require('mongoose')
const expressValidator = require('express-validator')
mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true , useUnifiedTopology: true })
const db = mongoose.connection
db.on('error', (error) => console.error(error))
db.once('open', () => console.log('Connected to Database'))
app.use(express.json())
const articlesRouter = require('./routes/articles')
app.use('/articles', articlesRouter)
const userRouter = require('./routes/users')
app.use('/register', userRouter)
app.set('view-engine', 'ejs')
app.use(express.urlencoded({ extended: false }))
app.get('/', (req, res) => {
res.render('index.ejs')
})
app.get('/login', (req, res) => {
res.render('login.ejs')
})
app.post('/login', (req, res) => {
})
app.get('/register', (req, res) => {
res.render('register.ejs')
})
app.listen(3000, () => console.log('Server Started'))
Users model
const mongoose = require('mongoose')
const bcrypt = require('bcrypt')
var userSchema = new mongoose.Schema({
firstName: String,
lastName: String,
email: String,
password: String,
permissionLevel: Number,
created: Date},
{ collection: 'Users'});
module.exports = mongoose.model('Users', userSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.getUserByEmail = function(email, callback){
var query = {email: email};
User.findOne(query, callback);
}
module.exports.getUserById = function(id, callback){
user.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback) {
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) throw err;
callback(null, isMatch)
});
}
users routes
const express = require('express')
const router = express.Router()
const Users = require('../models/users')
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy
//Register Page - GET
router.get('/register', (req, res) => {
res.render('register.hbs', {
pageTitle: 'register'
});
});
//Login Page - GET
router.get('/login', (req, res) => {
res.render('login.hbs', {
pageTitle: 'login'
});
});
//Register - POST
router.post('/', (req, res) => {
var firstName = req.body.firstName;
var lastName = req.body.lastName;
var email = req.body.email;
var password = req.body.password;
//validations
req.checkBody('firstName', 'Your First Name is Required').notEmpty();
req.checkBody('lastName', 'Your Last Name is Required').notEmpty();
req.checkBody('email', 'A valid email is required').isEmail();
req.checkBody('password', 'An Account Passowrd Is Required').notEmpty();
var errors = req.validationErrors();
if (errors) {
res.render('register', {
errors:errors
});
} else {
var newUser = new newUser({
firstName: firstName,
lastName: lastName,
email: email,
password: password,
});
User.createUser(newUser, function(err, user) {
if(err) throw(err);
console.log(user);
});
req.flash('success_message', "You are now registered!");
res.redirect('/login');
}
});
passport.use(new LocalStrategy({
email: 'email'
},
function(email, password, done){
Users.getUserByEmail(email, function(err, Users){
if(err) throw err;
if(!Users){
return done(null, false, {message: 'Unknown Email Address'});
}
Users.comparePassword(password, user.password, function(err, ismatch){
if(err) throw err;
if(ismatch){
return done (null, user);
} else {
return done(null, false, {message: 'Invalid Passowrd'});
}
});
});
}));
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
Users.getUserByID(id, function(err, user) {
done(err, user)
});
});
router.post('/login', passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/login',
successFlash: 'Welcome',
failureFlash: 'Invalid Email or Passowrd!'
}), function(req, res) {
res.redirect('/');
});
router.get('/logout', function(req, res) {
req.logout();
req.flash('Success_message', 'You are now logged out!')
res.redirect('/');
});
module.exports = router
I suspect the conflict is between the router /register and the my 'Users' collection. I'm just unable to pinpoint what the issue could be.
Any help would be greatly appreciated
Your userRouter is mounted on /users (from your code: app.use('/users', userRouter), meaning that all the routes you declared in the router are prefixed by /users).
Try calling POST /users/register.
You're using users routes file at /users route, so when you declare /register route in users routes file it become /users/register please send your REST API request to /users/register endpoint
Edit #2
I have made the following changes
In the mailer I've changed
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset-password/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n'
to
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/users/reset-password/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n'
and my routes from
// Reset Password Token link :get
router.get('/reset-password/:token', function(req, res) {
and
// Reset Password Token :post
router.post('/reset-password/:token', function(req, res, next) {
to
// Reset Password Token link :get
router.get('/users/reset-password/:token', function(req, res) {
and
// Reset Password Token :post
router.post('/users/reset-password/:token', function(req, res, next) {
I am still getting the GET error in the original question.
Edit #1
app.js
const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const hbs = require('hbs');
const expressValidator = require('express-validator');
const flash = require('connect-flash');
const session = require('express-session');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const fs = require('fs');
var app = express();
// Server port
const port = process.env.PORT || 3000;
// Server starting message
app.listen(port, () => {
console.log(`Server is up on port ${port}`);
});
// Views directory established and handbars engine
hbs.registerPartials(__dirname + '/views/layouts')
app.set('view engine', 'hbs');
// static assets rendered
app.use(express.static(__dirname + '/public'));
app.use('/users', express.static(__dirname + '/public'));
app.use('/dashboard', express.static(__dirname + '/public'));
// body-parser middleware
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(cookieParser());
// expressSession
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// passport
app.use(passport.initialize());
app.use(passport.session());
// expressValidator
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
};
}
}));
// Connect Flash
app.use(flash());
// Global Vars
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
next();
});
// server.log setup middleware
app.use((req, res, next) => {
var now = new Date().toString();
var log = `${now}: ${req.method} ${req.url}`
console.log(log);
fs.appendFile('server.log', log + '\n', (err) => {
if (err) {
console.log('Unable to append to server.log');
}
});
next();
});
// Routes
const routes = require('./routes/routes');
const users = require('./routes/users');
const dashboard = require('./routes/dashboard');
app.use("/", routes);
app.use("/users", users);
app.use("/dashboard", dashboard);
// Get year for footer
hbs.registerHelper('getCurrentYear', () => {
return new Date().getFullYear()
});
--
Original Question
I'm trying to implement password reset functionality in my app using the the following tutorial
I have made a few tweaks to suit my needs and the routes I want but at the moment I'm getting the following
--
Here is my current file structure
and here is my current code
user.js model
const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
var app = express();
if (app.get('env') === 'production') {
mongoose.connect(process.env.DATABASE_URL, { useMongoClient: true });
} else {
mongoose.connect('mongodb://localhost/pol-development', { useMongoClient: true });
}
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log("Connection has been established");
});
var UserSchema = mongoose.Schema({
schoolName: String,
schoolAddress: String,
schoolAddress2: String,
city: String,
zipCode: String,
addressCheck: Boolean,
postalAddress: String,
postalCity: String,
postalZipCode: String,
telephone: Number,
fax: Number,
email: { type: String, required: true, unique: true },
password: String,
schoolType: String,
schoolDistrict: String,
schoolRegion: String,
curriculum: String,
participationBefore: Boolean,
participationYears: Number,
directorName: String,
directorTelephone: Number,
directorEmail: String,
directorAttendanceRehersal: Boolean,
directorAttendanceEvent: Boolean,
schoolLiaisonName: String,
schoolLiaisonTelephone: Number,
schoolLiaisonEmail: String,
schoolLiaisonPosition: String,
schoolLiaisonOtherPosition: String,
schoolLiaisonTShirt: String,
schoolLiaisonTutorMentor: String,
attendanceRehersal: Boolean,
attendanceEvent: Boolean,
admin: Boolean,
});
UserSchema.pre('save', function(next) {
var user = this;
var SALT_FACTOR = 5;
if (!user.isModified('password')) return next();
bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.getUserByEmail = function(email, callback){
var query = {email: email};
User.findOne(query, callback);
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback) {
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
users.js routes
const express = require('express');
const router = express.Router();
const passport = require('passport');
const nodemailer = require('nodemailer');
const randomBytes = require('randombytes');
const async = require('async');
const LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
// Register :get
router.get('/register', (req, res) => {
res.render('register.hbs', {
pageTitle: 'Register'
});
});
// Register :post
router.post('/register', (req, res) => {
var schoolName = req.body.schoolName;
var schoolAddress = req.body.schoolAddress;
var schoolAddress2 = req.body.schoolAddress2;
var city = req.body.city;
var zipCode = req.body.zipCode;
var postalAddress = req.body.postalAddress;
var postalCity = req.body.postalCity;
var postalZipCode = req.body.postalZipCode;
var telephone = req.body.telephone;
var email = req.body.email;
var password = req.body.password;
var schoolType = req.body.schoolType;
var schoolDistrict = req.body.schoolDistrict;
var schoolRegion = req.body.schoolRegion;
var curriculum = req.body.curriculum;
var directorName = req.body.directorName;
var directorTelephone = req.body.directorTelephone;
var directorEmail = req.body.directorEmail;
var schoolLiaisonName = req.body.schoolLiaisonName;
var schoolLiaisonTelephone = req.body.schoolLiaisonTelephone;
var schoolLiaisonEmail = req.body.schoolLiaisonEmail;
var schoolLiaisonPosition = req.body.schoolLiaisonPosition;
var schoolLiaisonTShirt = req.body.schoolLiaisonTShirt;
var schoolLiaisonTutorMentor = req.body.schoolLiaisonTutorMentor;
// validations
req.checkBody('schoolName', 'The school name is required').notEmpty();
req.checkBody('schoolAddress', 'The school address is required').notEmpty();
req.checkBody('city', 'The city is required').notEmpty();
req.checkBody('zipCode', 'This zip code is required').notEmpty();
req.checkBody('telephone', 'A telephone number is required').notEmpty();
req.checkBody('email', 'An account email is required').notEmpty();
req.checkBody('email', 'This account email is not valid').isEmail();
req.checkBody('password', 'An account password is required').notEmpty();
req.checkBody('schoolType', 'A school type is required').notEmpty();
req.checkBody('schoolDistrict', 'A school district is required').notEmpty();
req.checkBody('schoolRegion', 'A school region is required').notEmpty();
req.checkBody('curriculum', 'A curriculum is required').notEmpty();
req.checkBody('directorName', 'A directors name is required').notEmpty();
req.checkBody('directorTelephone', 'A directors telephone is required').notEmpty();
req.checkBody('directorEmail', 'A directors email is required').notEmpty();
req.checkBody('directorEmail', 'This email is not valid').isEmail();
req.checkBody('schoolLiaisonName', 'A school representative name is required').notEmpty();
req.checkBody('schoolLiaisonTelephone', 'A school representative telephone is required').notEmpty();
req.checkBody('schoolLiaisonEmail', 'The school representative email is not valid').isEmail();
req.checkBody('schoolLiaisonEmail', 'A school representative email is required').notEmpty();
req.checkBody('schoolLiaisonPosition', 'A school representative position is required').notEmpty();
req.checkBody('schoolLiaisonTShirt', 'A school representative t-shirt size is required').notEmpty();
req.checkBody('schoolLiaisonTutorMentor', 'A school representative tutor/mentor is required').notEmpty();
var errors = req.validationErrors();
if (errors) {
res.render('register', {
errors:errors
});
} else {
var newUser = new User({
schoolName: schoolName,
schoolAddress: schoolAddress,
schoolAddress2: schoolAddress2,
city: city,
zipCode: zipCode,
postalAddress: postalAddress,
postalCity: postalCity,
postalZipCode: postalZipCode,
telephone: telephone,
email: email,
password: password,
schoolType: schoolType,
schoolDistrict: schoolDistrict,
schoolRegion: schoolRegion,
curriculum: curriculum,
directorName: directorName,
directorTelephone: directorTelephone,
directorEmail: directorEmail,
schoolLiaisonName: schoolLiaisonName,
schoolLiaisonTelephone: schoolLiaisonTelephone,
schoolLiaisonEmail: schoolLiaisonEmail,
schoolLiaisonPosition: schoolLiaisonPosition,
schoolLiaisonTShirt: schoolLiaisonTShirt,
schoolLiaisonTutorMentor: schoolLiaisonTutorMentor,
});
User.createUser(newUser, function(err, user) {
if(err) throw err;
console.log(user);
});
req.flash('success_msg', 'You are now registered, you can now login!');
res.redirect('/users/login');
}
});
passport.use(new LocalStrategy({
usernameField: 'email'
},
function(email, password, done) {
User.getUserByEmail(email, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {message: 'Unknown Email Address'});
}
User.comparePassword(password, user.password, function(err, ismatch){
if(err) throw err;
if(ismatch){
return done(null, user);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
});
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
// Login :get
router.get('/login', (req, res) => {
res.render('login.hbs', {
pageTitle: 'Login'
});
});
// Login :post
router.post('/login', passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
successFlash: 'Welcome!',
failureFlash: 'Invalid email or password.'
}), function(req, res) {
// res.redirect('/' + req.user.username);
res.redirect('/');
});
// Reset Password :get
router.get('/reset-password', function(req, res) {
res.render('reset-password', {
pageTitle: 'Reset Password',
User: req.user
});
});
// Reset Password :post
router.post('/reset-password', function(req, res, next) {
async.waterfall([
function(done) {
randomBytes(20, function(err, buf) {
var token = buf.toString('hex');
done(err, token);
});
},
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/reset-password');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
},
function(token, user, done) {
nodemailer.createTestAccount((err, account) => {
// create reusable transporter object using the default SMTP transport
if (process.env.NODE_ENV === 'production') {
transporter = nodemailer.createTransport({
host: "smtp.sendgrid.net",
port: 587,
auth: {
user: process.env.SENDGRID_USERNAME,
pass: process.env.SENDGRID_PASSWORD,
}
});
} else {
transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
auth: {
user: 'qkkvnabtziufbksa#ethereal.email',
pass: 'A4W9HF2WbhAav263VM',
}
});
}
// setup email data with unicode symbols
let mailOptions = {
from: 'password.reset' + process.env.GLOBAL_EMAIL || 'ben#benbagley.co.uk', // sender address
to: user.email, // list of receivers
subject: 'Reset Password Request', // Subject line
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + 'http://' + req.headers.host + '/reset-password/' + token + '\n\n' + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' // output
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
req.flash('success', 'An e-mail has been sent to ' + user.email + ' with further instructions.');
done(err, 'done');
res.redirect('/users/reset-password');
});
});
}
], function(err) {
if (err) return next(err);
res.redirect('/');
});
});
// Reset Password Token link :get
router.get('/reset-password/:token', function(req, res) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('/users/reset-password');
}
res.render('/', {
user: req.user
});
});
});
// Reset Password Token :post
router.post('/reset-password/:token', function(req, res, next) {
async.waterfall([
function(done) {
User.findOne({ resetPasswordToken: req.params.token, resetPasswordExpires: { $gt: Date.now() } }, function(err, user) {
if (!user) {
req.flash('error', 'Password reset token is invalid or has expired.');
return res.redirect('back');
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function(err) {
req.logIn(user, function(err) {
done(err, user);
});
});
});
},
function(user, done) {
nodemailer.createTestAccount((err, account) => {
// create reusable transporter object using the default SMTP transport
if (process.env.NODE_ENV === 'production') {
transporter = nodemailer.createTransport({
host: "smtp.sendgrid.net",
port: 587,
auth: {
user: process.env.SENDGRID_USERNAME,
pass: process.env.SENDGRID_PASSWORD,
}
});
} else {
transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
auth: {
user: 'qkkvnabtziufbksa#ethereal.email',
pass: 'A4W9HF2WbhAav263VM',
}
});
}
// setup email data with unicode symbols
let mailOptions = {
from: 'password.reset' + process.env.GLOBAL_EMAIL || 'ben#benbagley.co.uk', // sender address
to: user.email, // list of receivers
subject: 'Your password has been changed', // Subject line
text: 'Hello,\n\n' + 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' // output
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (err) => {
req.flash('success', 'Success! Your password has been changed.');
done(err);
});
});
}
], function(err) {
res.redirect('/');
});
});
// Logout
router.get('/logout', function(req, res) {
req.logout();
req.flash('success_msg', 'You are now logged out!');
res.redirect('/users/login');
});
module.exports = router;
new-password
{{> header }}
<div class="container">
{{> flash }}
<form action="/users/reset-password" method="post">
<div class="panel panel-default">
<div class="panel-heading">Reset Password</div>
<div class="panel-body">
<div class="form-group">
<label for="exampleInputEmail1">New Password</label>
<input type="password" class="form-control" placeholder="New Password" name="password" value="">
</div>
<div class="form-group">
<label for="exampleInputEmail1">Confirm Password</label>
<input type="password" class="form-control" placeholder="Confirm Password" name="confirm" value="">
</div>
<button type="submit" class="btn btn-primary">Update Password</button>
</div><!-- Panel Body -->
</div><!-- Panel Default -->
</form>
</div><!-- Container ends -->
{{> footer }}
Any help here would be appreciated.
What is expected here
After I click on the link in the email the token gets passed and redirect the user to the new-password page so they can change their password.
Not sure what else to try here.
You have this:
const users = require('./routes/users');
app.use("/users", users);
and inside your users.js you have this.
router.post('/reset-password/:token', function(req, res, next) {
You are trying to access that by going to:
`localhost:3000/reset-password/sdasdasdtokenblabla`
You should be going to:
`localhost:3000/users/reset-password/tokenblabla`
I will love to share my experience too with this error
Solution to Password Reset using django-rest-passwordrest in Django rest framework
I'm doing a tutorial and I'm stuck in the login area. When I'm login in with Passport.js it always executing "failureRedirect" in authenticate.
After trying to debug replacing the router.post('login') route I received the following message:
Error: null User: false Info: {"message":"Missing credentials"}
After Reading on some forums I think that the problem could be related to body-parser. I've been trying to solve the problem but I haven't been able yet. I'd appreciate the help of a most experienced node.js programmer.
The structure of the project is:
app.js
routes:
users.js
models:
user.js
user.js
var express = require('express');
var router = express.Router();
var multer = require('multer');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bodyParser = require('body-parser');
var User = require('../models/user');
var upload = multer({ dest: './uploads' });
// create application/json parser
var jsonParser = bodyParser.json();
// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false });
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
router.get('/register', function(req, res, next) {
res.render('register', {
title: 'Register'
});
});
router.get('/login', function(req, res, next) {
res.render('login', {
'title': 'Login'
});
});
router.post('/register', upload.single('profileimage'), function (req, res, next) {
//Get Form Values
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var password2 = req.body.password2;
// Check for Image Field
if(req.files && req.files.profileimage){
console.log('Uploading File...');
// File Info
var profileImageOriginalName = req.files.profileimage.originalname;
var profileImageName = req.files.profileimage.name;
var profileImageMime = req.files.profileimage.mimetype;
var profileImagePath = req.files.profileimage.path;
var profileImageExt = req.files.profileimage.extension;
var profileImageSize = req.files.profileimage.size;
} else {
// Set a Default Image
var profileImageName = 'noimage.png';
}
// Form Validation
req.checkBody('name', 'Name field is required').notEmpty();
req.checkBody('email', 'Email field is required').notEmpty();
req.checkBody('email', 'Email not valid').isEmail();
req.checkBody('username', 'Username field is required').notEmpty();
req.checkBody('password', 'Password field is required').notEmpty();
req.checkBody('password2', 'Passwords do not match').equals(req.body.password);
// Check for errors
var errors = req.validationErrors();
if(errors){
res.render('register', {
errors: errors,
name: name,
email: email,
username: username,
password: password,
password2: password2
});
} else {
var newUser = new User({
name: name,
email: email,
username: username,
password: password,
profileImage: profileImageName
});
// Create User
User.createUser(newUser, function (err, user) {
if(err) throw err;
console.log(user);
});
//Success Message
req.flash('success', 'You are now registered and may log in');
res.location('/');
res.redirect('/');
}
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(
function (username, password, done) {
User.getUserByUsername(username, function (err, user) {
if(err) throw err;
if(!user){
console.log('Unknown User');
return done(null, false, {message: 'Unknown User'});
}
User.comparePassword(password, user.password, function (err, isMatch) {
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
console.log('Invalid Password');
return done(null, false, {message:'Invalid Password'});
}
});
});
}
));
router.post('/login', jsonParser, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/users/login',
failureFlash: true //'Invalid username or password'
}), function (req, res) {
console.log('Authentication Successful');
req.flash('success', 'You are logged in');
res.redirect('/');
});
router.post('/login', passport.authenticate('local', function(err, user, info) {
console.log("authenticate");
console.log(err);
console.log(user);
console.log(info);
}), function (req, res) {
console.log('Authentication Successful');
req.flash('success', 'You are logged in');
res.redirect('/');
});
module.exports = router;
user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
mongoose.connect('mongodb://localhost/nodeauth');
var db = mongoose.connection;
// User Schema
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String,
required: true,
bcrypt: true
},
email: {
type: String
},
name:{
type: String
},
profileimage:{
type: String
}
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.comparePassword = function(candidatePassowrd, hash, callback) {
bcrypt.compare(candidatePassowrd, hash, function (err, isMatch) {
if(err) return callback(err);
callback(null, isMatch);
});
}
module.exports.getUserById = function (id, callback) {
User.findById(id, callback);
}
module.exports.getUserByUsername = function (username, callback) {
var query = {username: username};
User.findOne(query, callback);
}
module.exports.createUser = function (newUser, callback) {
bcrypt.hash(newUser.password, 10, function (err, hash) {
if(err) throw err;
// Set hashed pw
newUser.password = hash;
// Create User
newUser.save(callback);
});
}
app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var expressValidator = require('express-validator');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bodyParser = require('body-parser');
var multer = require('multer');
var flash = require('connect-flash');
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connection;
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// Handle File Uploads
// app.use(multer({dest:'./uploads'}));
var upload = multer({ dest: './uploads' });
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Handle Express Sessions
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// Passport
app.use(passport.initialize());
app.use(passport.session());
// Validator
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
};
}
}));
// app.use(expressValidator({
// errorFormatter
// }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
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 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;
Files on Dropbox:
https://www.dropbox.com/sh/ex26xxo85lfo0my/AADET-j6Ift0q-y-ecWCRUEba?dl=0
Thanks for your help :)
Please check the code here on https://github.com/rupalipemare/Mongoose-Demo, wherein there is complete example demonstrating passport authentication.
First.. Please try to modularize code. Putting a functionalities in different files can help you track bugs faster. Second why are there two POST calls to login route? Remove the first one and no need to send jsonParser. Yo have declared to serialize and deserialize user. So passport will handle rest.
I am creating multiplayer game, where I have login system as well. I want to update my user's rating using db.collection.update(), but it is not working. There is no error, just when I write username of my player It says "Unknown User". I write it in my app.js. Besides app.js I have 3 more files for my user.
My app.js
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var flash = require('connect-flash');
var fs = require('fs');
var session = require('express-session');
var mongo = require('mongodb');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/loginapp');
var db = mongoose.connection;
var routes = require('./routes/index');
var users = require('./routes/users');
var User = require('./models/users');
// Init App
var app = express();
var server = require("http").Server(app);
// BodyParser Middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
// Express Session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
User.getUserByRating(rating, function(err)
{
if(err) throw err;
});
});
}));
// Connect Flash
app.use(flash());
// Global Vars
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
console.log(req.user);
next();
});
app.use('/', routes);
app.use('/users', users);
User.collection.update(
{ username: "example2" },
{
name: "qq",
rating: 1
}
)
My users.js
var express = require('express');
var router = express.Router();
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/users');
// Register
router.get('/register', function(req, res){
res.render('register');
});
// Login
router.get('/login', function(req, res){
res.render('login');
});
//Register User
router.post('/register', function(req, res){
var name = req.body.name;
var email = req.body.email;
var username = req.body.username;
var password = req.body.password;
var password2 = req.body.password2;
var rating = req.body.rating;
// Validation
req.checkBody('email', 'Email is required').notEmpty();
req.checkBody('email', 'Email is not valid').isEmail();
req.checkBody('username', 'Username is required').notEmpty();
req.checkBody('password', 'Password is required').notEmpty();
req.checkBody('password2', 'Passwords do not match').equals(req.body.password);
var errors = req.validationErrors();
if(errors)
{
res.render('register',{
errors:errors
});
} else
{
var newUser = new User({
name: name,
email:email,
username: username,
password: password,
rating: 1000
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
});
req.flash('success_msg', 'You are registered and can now login');
res.redirect('/users/login');
}
});
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.getUserById(id, function(err, user) {
done(err, user);
});
});
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect:'/users/login',failureFlash: true}),
function(req, res) {
res.redirect('/');
});
router.get('/logout', function(req, res){
req.logout();
req.flash('success_msg', 'You are logged out');
res.redirect('/users/login');
});
module.exports = router;
My model(again users.js, but in another folder)
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
rating:
{
type: Number
}
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(newUser.password, salt, function(err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.getUserByRating = function(rating, callback){
User.findOne({ rating : rating}, callback);
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
callback(null, isMatch);
});
}
My index.js
var express = require('express');
var router = express.Router();
// Get Homepage
router.get('/', ensureAuthenticated, function(req, res){
res.render('index');
});
function ensureAuthenticated(req, res, next){
if(req.isAuthenticated()){
return next();
} else {
//req.flash('error_msg','You are not logged in');
res.redirect('/users/login');
}
}
module.exports = router;
Thanks a lot in advance. I will be grateful for any help.
Your update code uses raw mongo interface:
User.collection.update(
{ username: "example2" },
{
name: "qq",
rating: 1
}
)
This code replace your document as whole(all missed fields like password and etc will be lost).
You may be want to use followed: {$set: {name: 'qq', rating: 1}}
Or use mongoose interface:
User.update({username: 'example2'}, {name: 'qq', rating: 1});
It will add $set part automatically, if you don't specify safe = false in your model.
Check actual database state before you start to do anything in your code. There are some users incosistent with your model schema, and may be no user with example2 name.