Password confirmation with Passport - node.js

I've created a basic user registration form which works fine but I need to add a confirm password field.
My form is as follows:
<div class ="container form">
<div class="jumbotron form"><h2><i class="fa fa-user-plus" aria-hidden="true"></i> Signup</h2></div>
<form action = "/register" method="POST">
<div class="form-group">
<i class="fa fa-user" aria-hidden="true"></i>
<label for="username">Username</label>
<input type = "text" class = "form-control" placeholder = "Enter username" name="username">
</div>
<div class="form-group">
<i class="fa fa-key" aria-hidden="true"></i>
<label for="password">Password</label>
<input type = "password" class ="form-control" placeholder = "Enter password" name="password1">
</div>
<div class="form-group">
<i class="fa fa-key" aria-hidden="true"></i>
<label for="password">Confirm password</label>
<input type = "password" class ="form-control" placeholder = "Enter password" name = "password">
</div>
<div class="form-group">
<i class="fa fa-picture-o" aria-hidden="true"></i>
<label for="img">Image</label>
<input type = "text" class ="form-control" placeholder = "Enter image URL" name = "image">
</div>
<button type ="submit" class="btn btn-primary btn-lg">Signup</button>
</form>
</div>
So when a user hits submit, I obviously need the 2 password inputs to match and an error to be thrown if they don't.
I'm using Passport for authenitcation. I have the following setup:
// passport configuration
app.use(require("express-session")({
secret: "maidenJones",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(expressSanitizer());
app.use(function(req, res, next){
res.locals.currentUser = req.user;
res.locals.error = req.flash("error");
res.locals.success = req.flash("success");
next();
});
Register route:
router.post("/register", function(req, res){
var newUser = new User({username: req.body.username, image: req.body.image});
User.register(newUser, req.body.password, function(err, user){
if(err){
res.redirect("/blogs");
console.log(err);
}
passport.authenticate("local")(req, res, function(){
res.redirect("/blogs");
});
});
});
Not sure where to start to implement the password confirmation check

You have to move your registration logic inside the passport LocalStrategy and then use that strategy as a middleware in your routes.
Example:
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'passwd'
},
function(req, username, password, done) {
// User register logic
}
));
router.post('/register',
passport.authenticate('local', { failureRedirect: '/register' }),
function(req, res) {
res.redirect('/blogs');
});
more info here: passport-localstrategy

passport.use('local.signup', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function (req, email, password, done) {
//All validation logic comes here
let password1 = req.body.password;
let password2 = req.body.password2;
req.checkBody('email', 'Invalid email').notEmpty().isEmail();
req.checkBody('password', 'Password must be more than 4 characters')
.not().isEmpty().isLength({ min: 4 });
let errors = req.validationErrors();
//just to see the output in your console
console.log(password1);
console.log(password2);
if (errors) {
let messages = [];
errors.forEach(function (error) {
messages.push(error.msg);
});
return done(null, false, req.flash('error', messages));
} else if (password1 !== password2) {
return done(null, false, req.flash('error', 'Password and Confirm Password must match'));
}
// You can then continue your code logic(submitting to database)

Related

Form validation with flash messages in express js

I am trying to validate a form in express js before i post it onto the mongodb which i am using as a backend. My user.js for registration page looks something like this -
router.post('/register', (req, res) => {
userreg.register(
// eslint-disable-next-line new-cap
new userreg({
firstname: req.body.firstname,
lastname: req.body.lastname,
username: req.body.email,
usn: req.body.usn, // validate so that no space is taken or else request modal wont work
course: req.body.course,
}),
req.body.password,
(err) => {
if (err) {
console.log(err);
res.render('register', { user: 'error' });
} else {
console.log('no error');
res.render('submit-success', { username: req.body.firstname });
}
}
);
});
and my register.ejs looks something like this -
<form class="user" action = '/users/register' method="POST">
<div class="form-group row">
<div class="col-sm-6 mb-3 mb-sm-0">
<input type="text" class="form-control form-control-user" id="exampleFirstName" name="firstname" placeholder="First Name">
</div>
<div class="col-sm-6">
<input type="text" class="form-control form-control-user" id="exampleLastName" name="lastname" placeholder="Last Name">
</div>
</div>
<div class="form-group">
<input type="email" class="form-control form-control-user" id="exampleInputEmail" name="email" placeholder="Email Address">
</div>
<div class="form-group">
<input type="text" class="form-control form-control-user" id="exampleInputUSN" name="usn" placeholder="USN">
</div>
<div class="form-group">
<select class=" form-control selectpicker" name="course">
<optgroup label="Course"></optgroup>
<option selected hidden disabled>Course</option>
<option value="mca">Computer Applications</option>
<option value="mba">Business Administration</option>
</optgroup>
</select>
</div>
<div class="form-group">
<input type="password" class="form-control form-control-user" id="exampleInputPassword" name="password" placeholder="Password">
</div>
<div class="text-center">
<input type="submit" class = "btn btn-primary btn-user" value="Register">
</div>
</form>
By going through many sources on the internet(since i'm very very new to express js and im doing it as a part of my college project and since i can't consult any teachers for assistance during lockdown times) , I got to know that the validation part has to be implemented in user.js. Please help me with the code for validation and also displaying flash messages if field empty for atleast one field so that i can have a start atleast.
Thank you in advance
EDIT :
I Used the express-validator and ended up with the following changes -
var flash = require('connect-flash');
var app = express();
app.configure(function () {
app.use(express.cookieParser('keyboard cat'));
app.use(express.session({ cookie: { maxAge: 60000 } }));
app.use(flash());
});
app.get('/flash', function (req, res) {
// Set a flash message by passing the key, followed by the value, to
req.flash().
req.flash('info', 'There is an Error!')
res.redirect('/');
});
app.get('/', function (req, res) {
// Get an array of flash messages by passing the key to req.flash()
res.render('index', { messages: req.flash('info') });
});
const { check, validationResult } = require('express-validator');
router.post('/register', [
check('firstname', 'Please enter your first
name').exists().trim().escape().not().isEmpty(),
check('lastname', 'Please enter your last
name').exists().trim().not().isEmpty(),
check('username', 'Please enter an
email').exists().trim().not().isEmpty(),
check('usn', 'Please enter USN').exists().trim().not().isEmpty(),
check('course', 'Please enter Course').exists().trim().not().isEmpty(),
check('password', 'Please enter
password').exists().trim().not().isEmpty(),
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('message', `${errors}`);
res.redirect('/users/register');
} else {
userreg.register(
// eslint-disable-next-line new-cap
new userreg({
firstname: req.body.firstname,
lastname: req.body.lastname,
username: req.body.email,
usn: req.body.usn, // validate so that no space is taken or else
request modal wont work
course: req.body.course,
})),
res.render('submit-success', { username: req.body.firstname });
}
}
);
And as a result , the if (!errors.isEmpty()) is being invoked but there is no flash message being displayed. Am i missing something else ?
I am assuming you are using connect-flash.
const { check, validationResult } = require('express-validator');
router.post('/register', [
check('firstname', 'Please enter your first name').exists().trim().escape().not().isEmpty(),
check('lastname', 'Please enter your last name').exists().trim().not().isEmpty(),
check('email', 'Please enter an email').exists().trim().not().isEmpty(),
// ...
], (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
req.flash('message', `${errors}`);
res.redirect('register');
}
else {
// your code here!
}
});
You might want to consider creating middleware to handle validation errors, to make your code cleaner.

ReactJs and Passport Auth

m trying to make auth system with react and Passport js
My passport look like this:
let passport = require('passport');
let User = require('../models/user');
let localStorage = require('passport-local').Strategy;
passport.serializeUser(function(user, done){
done(null, user.id)
});
passport.deserializeUser(function(id, done){
User.findById(id, (err, user) => {
done(err, user)
})
});
passport.use('local.signup', new localStorage({
usernameField: 'email', passwordField: 'password', passReqToCallback: true
}, function(req, email, password, done){
//Check valid
req.checkBody(req.body.email, 'Invalid email').notEmpty().isEmail();
req.checkBody(req.body.password, 'Invalid password').notEmpty().isLength({min: 4});
req.checkBody(req.body.name, 'Name is require!').notEmpty();
let errors = req.validationErrors(); //Get all errors for checkBody
if(errors){
let messages = [];
errors.forEach(function(error){
messages.push(error.msg)
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email': req.body.email}, function(err, user){
if(err) return done(err);
if(user) return done(null, false, {message: 'Email is already in use'});
var newUser = new User();
newUser.email= req.body.email;
newUser.password = newUser.encryptPassword(req.body.password);
newUser.name = req.body.name;
newUser.save((err, user) => {
if(err) return done(err);
return done(null, user);
})
})
}));
My route file:
const express = require('express');
const passport = require('passport');
let router = express.Router();
let User = require('../models/user');
router.post('/signup', passport.authenticate('local.signup', {
failureRedirect: '/', failureFlash: true
}), function(req, res,next){
console.log('Yes signUp');
});
module.exports = router;
React file:
handleChange = ev => {
this.setState({[ev.target.name]: ev.target.value});
}
onSubmit = ev => {
ev.preventDefault();
let user = {
name: this.state.name,
email: this.state.email,
password: this.state.password
}
axios.post('http://localhost:3001/signup', user)
.then(res=> { console.log(res) })
.catch(err=> { console.error(err) })
}
render() {
return (
<div className="container login-container">
<div className="title-login text-center">Login</div>
<hr/>
<div className="login-form">
<div className="form-group">
<input type="email" className="form-control" name="email" value={this.state.email} placeholder="Enter your Email.." onChange={this.handleChange} />
</div>
<div className="form-group">
<input type="text" className="form-control" name="name" value={this.state.name} placeholder="Enter your Name.." onChange={this.handleChange} />
</div>
<div className="form-group">
<input type="password" className="form-control" name="password" value={this.state.password} placeholder="Enter your password.." onChange={this.handleChange} />
</div>
<button className="btn btn-outline-primary btn-block" onClick={this.onSubmit}>Send</button>
</div>
</div>
)
}
The error is:
OPTIONS http://localhost:3001/ 404 (Not Found) signup:1 Failed to load
http://localhost:3001/: Response for preflight has invalid HTTP status
code 404. index.js:2178 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
Help!

Passport local auth plus passport mongoose local are not accepting email as username

I am using passport local strategy and passport mongoose local to create a user and check user authentication. However, I wanted to explore the option using email instead of username. I followed what the document says and I am getting unauthorized. Can someone tell me why I am getting an error, and it works if I just use the username as login.
From passport-local-mongoose
Note: usernameField: specifies the field name that holds the username. Defaults to 'username'. This option can be used if you want to use a different field to hold the username for example "email".
And from passport local strategy
By default, LocalStrategy expects to find credentials in parameters named username and password. If your site prefers to name these fields differently, options are available to change the defaults.
I have tried to set both true at the same time and I also have tried to set one true and another one off. I will get the same error
express 4.16.0
express-session 1.15.6
mongoose 5.1.2
passport 0.40
passport local 1.0.0
passport local mongoose 5.0.0
passport.js
module.exports = function (passport, LocalStrategy, User) {
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true,
session: true
},
function(req, username, password, done) {
return done(null, req.user);
}
));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
};
model/User.js
var UserSchema = new mongoose.Schema({
name: { type: String, required: true, default: ''},
username: { type: String, unique: true, uniqueCaseInsensitive: true, required: true, default: ''},
email: { type: String, required: true, unique: true, uniqueCaseInsensitive: true, default: ''},
profileImage:{ type: String, default: ''},
timestamp: {type: String, default: () => moment().format("dddd, MMMM Do YYYY, h:mm:ss a") }
});
UserSchema.plugin(passportLocalMongoose, {usernameField: 'email'});
UserSchema.plugin(uniqueValidator);
module.exports = mongoose.model('UserSchema', UserSchema);
signinForm.js
<form class="form-signin" action="/users/signup" method="POST" enctype='multipart/form-data'>
<h1 class="h3 mb-3 font-weight-normal">Please sign up</h1>
<label for="inputName" class="sr-only">Name</label>
<input type="bane" id="inputName" class="form-control" placeholder="Name" name='name' required autofocus />
<label for="inputUsername" class="sr-only">Username</label>
<input type="bane" id="inputUsername" class="form-control" placeholder="Username" name='username' required autofocus />
<label for="inputEmail" class="sr-only">Email</label>
<input type="email" id="inputEmail" class="form-control" placeholder="Email" name='email' required autofocus />
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" name='password' required autofocus/>
<label for="inputConfirmPassword" class="sr-only">Confirm Password</label>
<input type="password" id="inputConfirmPassword" class="form-control" placeholder="Confirm Password" name='confirmPassword' required autofocus/>
<input type='file' class='form-control' id='inputFile' name='profileImage' />
<div style="height: 10px"></div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
</form>
routes/users.js
router.post('/signup', upload.single('profileImage'), function(req, res, next) {
const name = req.body.name;
const email = req.body.email;
const password = req.body.password;
const confirmPassword = req.body.confirmPassword;
if (req.file) {
console.log('Uploading File...');
var profileImage = req.file.filename;
} else {
console.log('No File Uploaded... Setting to no image');
var profileImage = 'noimage.jpg';
}
UserController.createUser(req.body, function(err, user) {
if (err) {
res.json({
err: err
});
return;
}
passport.authenticate('local')(req, res, function() {
//res.render('index', {currentUser: user, title: 'Product Page' });
res.redirect('/');
return;
});
return;
})
});
I ended up getting authorized and 401
Thanks in advance.
Try to remove the 'return' at the end of UserController.createUser(), you need to wait for the result of passport.authenticate()

nodes passport Error: Unknown authentication strategy "local-login"

I have been trying to get local authentication work with passport on nodejs and as far as i can tell all of my code it is correct but i keep getting the same annoying error about "unknown authentication strategy so maybe someone else can help me with this problem my code is shown below.
Here is my code for passport configuration in nodejs.
var passport = require('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 : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done) {
process.nextTick(function() {
User.findOne({ 'local.username' : username}, function(err, user) {
if (err)
return done(err);
if(user) {
return done(null, false, req.flash('signupMessage', 'That Username is already taken.'));
}
else {
var newUser = new User();
newUser.local.username = username;
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 : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password,done) {
User.findOne({ 'local.username' : username}, 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', 'Oops! Wrong password.'));
return done(null, user);
});
}));
};
And here is the post on the server side.
app.post('/signin', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
And here is the form in the html doc
<div id="signin">
<form class="form-horizontal" method="POST" action="/signin">
<div class="form-group">
<label class="control-label col-sm-2">Username:</label>
<div class="col-xs-3">
<input type="text" class="form-control"></input><br>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Password:</label>
<div class="col-xs-3">
<input type="password" class="form-control"></input><br><br>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default btn-lg">Sign In</button><br><br>
</div>
</div>
</form>
<div id="accountlinks">
Create Account<br>
Forgot Password
</div>
</div>
Can anyone please help me by telling me what i have done wrong. thanks
require('./config/passport')(passport);
Change the path of the file. Without this working, passport's configurations will not be passed to the routes.
Here is a snippet of where the line should be located:
// server.js
// configuration
===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
I also had the same problem but when I put this line of code after the app.use(flash()) it worked:
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
require('./config/passport')(passport);

Flash message in node js

I want a login page where the user enters their username and password, if it match then login is successful otherwise I want to show the flash message.
I've tried many different ways of doing this but couldn't find the correct way.
router.get('/login', function (req, res) {
res.render('login', {
layout: 'layouts/main/subpages',
topimagetype: 'home',
title: 'Log In',
message: req.flash('loginMessage')
});
});
You use the connect flash which is really simple to use.
Install the connect-flash via npm.
Here i give you example might be its works for you.
index.js // Router
router.get('/login', function (req, res) {
res.render('login', {
layout: 'layouts/main/subpages',
topimagetype: 'home',
title: 'Log In',
message: req.flash('loginMessage')
});
});
Passport.js // Configuration file
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function (req, email, password, done) {
pool.getConnection(function (err, connection) {
connection.query("SELECT * FROM user WHERE user_name = '" + email + "'", function (err, rows) {
if (err)
return done(err);
if (!rows.length) {
return done(null, false, req.flash('loginMessage', 'No user found.'));
}
if (!(passwordHash.verify(password, rows[0].password)))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
var userType={};
userType.super=false;
userType.admin=false;
userType.normal=false;
if (rows[0].Roll_id == 1) {
userType.super=true;
} else if (rows[0].Roll_id == 2) {
userType.admin=true;
}
else {
userType.normal=true;
}
rows[0].type=userType;
rows[0].created_date = rows[0].created_date.toDateString();
return done(null, rows[0]);
});
});
}));
Html View
<div class="login">
<div class="login-screen">
<div class="container">
{{#message}}
<div style="margin-left: 35%; width: 30%;">
<div class="alert alert-danger">{{ message }}</div>
</div>
{{/message}}
<section class="main">
<form action="/login" method="post" role="form" class="form-1">
<p class="field">
<input type="text" name="email" placeholder="email" id="login-name">
<i class="icon-user icon-large"></i>
</p>
<p class="field">
<input type="password" name="password" placeholder="password" id="login-pass">
<i class="icon-lock icon-large"></i>
</p>
<p class="submit">
<button type="submit" name="submit"><i class="icon-arrow-right icon-large"></i></button>
</p>
</form>
</section>
</div>

Resources