I am creating a user login. I am able to have the user sign up and when the user sings up his password is encrypted before it is saved in the database.
When that same user tries to log in, I am getting an "invalid password".
This is because it is comparing the user input to an encrypted password in the database. Example if password is 1234, then in database it is saved as "$2a$104$0301". When the user tries to log in, the user input which is "1234" is compared to "2a$104$0301". How would I fix?
Here is my code for login:
var LocalStrategy = require('passport-local').Strategy;
var User = require('../Models/users.js');
var bcrypt = require('bcrypt-nodejs');
module.exports = function(passport){
passport.use('login', new LocalStrategy({
passReqToCallback : true
},
function(req, username, password, done){
User.findOne({'username' : username},
function(err, user){
if(err)
return done(err);
if(!user){
console.log('User Not Found with username: '+username);
return done(null, false,
req.flash('message', 'User Not Found.'));
}
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done (null, false,
req.flash('message', 'Invalid Password'));
}
return done(null, user);
}
);
})
);
var isValidPassword = function(user, password){
var result = bcrypt.compareSync(password, user.password);
if (result) {
console.log("Password correct");
} else {
console.log("Password wrong");
}
return result;
}
}
compareSync method takes only 2 arguments and returns a boolean value true or false.
You should perform the check like this:
var result = bcrypt.compareSync(password, user.password);
if (result) {
console.log("Password correct");
} else {
console.log("Password wrong");
}
Really late to the party, however I just had this same problem and the reason it wasn't working for me was that I had encrypted the input password before trying to compare with the already encrypted 'user.password'.
Once I realised there was no need to encrypt the input password, the compareSync worked perfectly.
From bcrypt - npm:
To check a password:
// Load hash from your password DB.
bcrypt.compareSync(myPlaintextPassword, hash); // true
bcrypt.compareSync(someOtherPlaintextPassword, hash); // false
The "compareSync" function counters timing attacks (using a so-called 'constant-time' algorithm). In general, don't use the normal JavaScript string comparison functions to compare passwords, cryptographic keys, or cryptographic hashes if they are relevant to security.
I had a similar problem, when executing bcrypt.compareSync, it did not hash the password of the user who was without bcrypt, the problem was the order in which I had them, which was the following:
bcrypt.compareSync (passwordHash, password)
I solved it by organizing it, first the password and then the passwordHash, which would look like this:
bcrypt.compareSync (password, student.password)
I hope it helps someone, good code! <3 #sebasrestrepom
Related
I am currently working on a login system with Nodejs, Express & MongoDB. Everything works except the values in the database are coming up as undefined. At the two console.log statements where "database ___" is stated, the result is undefined. Not too sure why, from some testing it seems that the user inputted values work fine so I don't know why it's returning undefined.
app.post("/login", (req, res) => {
//Get user fields
const userEmail = req.body.loginEmail;
const userPass = req.body.loginPassword;
//Is user in database?
User.find({ email: userEmail }, (err, user) => {
console.log("database email: " + user.email)
if (!err) {
//Compare password to database password
bcrypt.compare(userPass, user.password, (err, result) => {
console.log("database password: " + user.password);
//If user pass in database, check if verified & redirect to success
if (userPass === user.password) {
if (user.isVerified) {
res.redirect("/success");
} else {
res.send(
"You are not verified. Please check your email to access your account."
);
}
} else {
res.send("Incorrect password");
}
});
} else {
res.send(err);
}
});
});
Mongoose will return an array as the second argument to the callback function when you use find(). If you use findOne() a single document will be returned instead.
I am very new to coding and am writing a personal project using node.js, express, mongoDB, and mongoose. I wrote most of it myself, however I hired someone to help me with the more advanced parts. I have lost contact with him and went back under the hood to create an admin panel I could use to write blog posts and other things. I am trying to write a middleware that only allows myself access to the route. However it is not working.
function adminAuth(req, res, next){
if(req.user.isAdmin){
return next();
} else {
res.redirect("/");
}
}
I am a bit confused of the syntax he has used to create a user schema and I am not sure how to add this isAdmin key value pair. Any help updating my users with an isAdmin key value would be extremely appreciated, and also helping me finish the middleware as (req.user.isAdmin) is not working! (If I do not provide the necessary code, please excuse my inexperience and tell me what you would like to see).
Here is the Auth route the coder I hired wrote that I am having trouble deciphering how to pass in new data to the user model.
const isAdmin = false;
const passwordHash = await bcrypt.hash(req.body.password, saltRounds);
const db = client.db(dbName);
const col = db.collection('users');
const user = {
email, firstName, lastName, password: passwordHash, isAdmin,
};
local strategy
module.exports = function localStrategy() {
passport.use(new Strategy(
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, (req, email, password, done) => {
const url = process.env.MONGOLAB_URI;
const dbName = 'giftgrab';
(async function addUser() {
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
const col = db.collection('users');
const user = await col.findOne({ email });
debug('Found user by email');
debug(user);
if (!user) {
req.flash('error', 'The username or password is wrong');
done(null, false);
} else {
const match = await bcrypt.compare(password, user.password);
if (match) {
done(null, user);
} else {
req.flash('error', 'The username or password is wrong');
// we pass null because it did not error, just failed
done(null, false);
}
}
} catch (e) {
debug(e.stack);
}
client.close();
}());
}
Here is the Auth route the coder I hired wrote that I am having trouble deciphering how to pass in new data to the user model.
// add logic to check if the user is admin
const isAdmin = false;
// user data collected here. If you want to add an "isAdmin" property, this is the right place
const user = {
email, firstName, lastName, password: passwordHash, isAdmin,
};
// checking if the user already exists
const check = await col.findOne({ email });
if (check) {
req.flash('error', 'The user with this email already exists');
res.redirect('back');
} else {
// the user does not exist, insert a new one and authenticate
const results = await col.insertOne(user);
req.login(results.ops[0], () => {
res.redirect('/');
});
}
This is what related to adding the isAdmin property. In order to use req.user and req.isAuthenticated() you are going to need Passport.js. The user data stored in you session (req.user) is defined by your passport strategy so if you want to use the isAdmin property this way, you are going to need to set it there.
I want to create function which will changing password. So in first place I have to compare old password with actually user password in db. Here is the problem, I write inside router function but it is not called. Can someone help me, and tell how could I call it to get answer that old password is equall with password user?
router.post('/change-password', function (req, res, next) {
console.log(req.body)
User.comparePassword(req.body.oldPpassword, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
You shouldn't be saving the password in the DB, that is unsafe. You should hash it in node and then save the hashed password to the DB. Then when you want to check a user, you hash the new password they gave you and compare that to the hashed one in the DB. You never, never store unhashed passwords. That is a recipe for disaster.
Libraries like bcrypt make this easy.
Having an awful time trying to compare passwords using bcryptjs so I can sign a JWT but trying to login I can't compare to sign the token and send to the client.
Problem
I can hash a password and store into the DB, where I'm having issues is using the .compare() method and passing in the hash parameter. I'm not quite sure what to pass in as the hash value.
Technology:
NodeJS: 5.4.1
bcryptjs: 2.3.0
express: 4.14.0
body-parser: 1.15.2
MongoDB: 3.2.5
mongoose: 4.6.1
user.routes.js
var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
var salt = bcrypt.genSaltSync(10);
var config = require('../config/database');
User = require('../models/user.model.js');
// Create new User
router.post('/', function(req, res){
var user = req.body;
if(!req.body.email || !req.body.password){
res.json({success: false, message: 'Please pass email and password'});
} else {
User.addUser(user, function(err, user){
if(err){
res.send(err);
}
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(user.password, salt, function(err,hash){
user.password = hash;
user.save();
console.log('new user', user);
res.json({success: true, message: 'Create user successful'});
})
})
});
}
});
Getting errors during password compare:
// Authenticate a User
//email: test#test.com
//password: password
router.post('/login', function(req, res){
User.findOne({ email: req.body.email }, function (err, user){
if (err){
res.send(err);
}
if(!user){
res.json({ success: false, message: 'Authentication failed. User not found'});
} else if (user) {
// where does this hash value get defined and passed in?
bcrypt.compare(req.body.password, hash, function(err, res){
if(user.password != req.body.password){
console.log('password incorrect');
//res.json({ success: false, message: 'Authentication failed. Password incorrect'});
} else {
var token = jwt.sign({
email: user.email
}, config.secret, {
expiresIn: 60 // expressed in seconds
});
console.log('token contents', token);
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
});
}
});
});
The hash value that you have to pass to the compare method is the one you got when you called bcrypt.hash method. I suppose you saved that hash associated to the user in some DB, so you have to get that hash and pass it to compare method as second parameter.
I think you are doing wrong the comparison in the callback of the compare method. You shouldn't compare passwords, the compare method does that for you. You just have to check if res is true or false. If it is true, then passwords are the same, other case they are different.
If you have more doubts about the implementation in this article you have a very simple example about that:
https://solidgeargroup.com/password-nodejs-mongodb-bcrypt?lang=es
It is written with promises, but it's very easy to understand.
Hello so I have the following code in my passport.js:
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
nameField: 'fullname',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done, fullname) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.local.email = email;
newUser.local.password = password;
newUser.local.fullname = fullname;
newUser.local.role = "default";
// save the user
newUser.save(function(err) {
if (err) {
throw err;
}
console.log(newUser);
return done(null, newUser);
});
}
});
});
}));
And I need to save the fullname into the database but unfortunately doesn't add because is the last parameter, after done. But if ill put fullname before done, the return done is is not found and gives me a application crash.
What do you think can be a solution?
You can retrieve the fullname from the req param. If you are using bodyparser then it is as simple as req.body.fullname. Use that where you need it. You need to make sure you are sending the fullname from the form with the email and password.
Local strategy for passport doesn't support other inputs than the usernameField and passwordField. If you need other inputs from the user you need to retrieve them from the original request.