Can't compare password with hash Passport NodeJS - javascript

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.

Related

How to do user login correctly with nodejs and express

I am very new to web development, and have been using Google as a guide.
If I put a wrong login that does not match what I have in my database, the website just gets stuck and keeps trying to “load”. I also am confused on how to do token-based authentication for login and would love some more guidance on that, the guide I am following talks about database encryption and OAuth 2.0 with Google.
If the user logs in with a username and password that is not correct, I just want it to give an error and reload back to login.ejs.
Thank you for any help!
The issue might be you are not returning anything when foundUser is null or if the password doesn’t match.
If there is any error you can redirect it to the /login route with query param (err) which can be read by the client using JS at page load. If there is a nonempty query param err then read it and show it in some popup.
res.redirect("/login?err=The username does not exist");
//connect to mongodb
mongoose.connect("mongodb://localhost:27017/userDB", {
useNewUrlParser: true
});
const userSchema = {
username: String,
password: String
};
const User = new mongoose.model("User", userSchema);
app.get("/", function(req, res) {
res.render("home"); //render home.ejs
});
app.get("/login", function(req, res) {
res.render("login"); //render login.ejs
});
app.post("/login", function(req, res) {
const username = req.body.username;
const password = req.body.password;
try {
User.findOne({
username: username
}, function(err, foundUser) {
if (err || !foundUser) {
return res.redirect("/login?err=The username does not exist");
}
if (foundUser.password !== password) {
// you can use bcryptjs for hashing and comparing hashed values.
return res.redirect("/login?err=The username or password is invalid");
}
res.redirect("/counter");
});
} catch (error) {
res.redirect("/login?err=something went wrong!");
}
});
You can read more about handling authentication in nodeJS here. also check passportjs

compare password with bCrypt returned false

I hash my password and save a user into db (using passport). Now I wrote an api (without passport) try to compare the password, it returned false although I key in the same string. Just curious why does it so? I doubt I know about how bCrypt works now. My code as below.
my model
module.exports.comparePassword = function(candidatePassword, hash, callback){
bCrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err){
return callback(err);
} else {
console.log("model: " + isMatch)
callback(null, isMatch);
}
});
}
controller
http://pastebin.com/jCB4YUy0
Figured it out. I need no to hash the password. The bCrypt module has that built in.

Node bCrypt.compareSync

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

Passport.js is not passing user to request in req.login()

My passport.js configuration goes like so:
const Local = require("passport-local").Strategy;
const USMODEL = require("../models/user.js");
passport.serializeUser(function(user, done) {
console.log("SERIALIZING USER");
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log("DESUSER", id);
var US = mongoose.model("RegUser", USMODEL);
US.findById(id, function(err, user) {
done(err, id);
});
});
passport.use("local-login", new Local({
usernameField: "email",
passwordField: "password",
passReqToCallback: true
},function(req, email, password, done) {
var US = mongoose.model("RegUser", USMODEL);
US.findOne({"email": email}, function(err, user){
if(err) throw err;
if(!user) return done(null, false);
if(!user.validPassword(password)) {
console.log("password not valid");
return done(null, false);
}
return done(null, user);
});
}));
I'm changing the mongoose model within each function because I juggle with multiple collections at a time and I like to have complete control of what's going on.
My router.js file has the following paths that make use of the passport middleware:
app.get("/user/login", function(req, res) {
res.render("signin");
});
app.post('/user/login', function (req, res){
passport.authenticate('local-login', function(err, user, info){
if (err) return res.redirect("/");
if (!user) return res.redirect('/');
else {
req.login(user, function(err) {
if (err) return next(err);
console.log("Request Login supossedly successful.");
return res.redirect('/admin/filter');
});
}
})(req, res);
});
Which, upon successful authentication, redirects to /admin/filter in the same router that goes like so.
app.get("/admin/filter", isLoggedIn, function(req, res){
//rendering stuff here
});
Now, the admin/filter request goes past a middleware called isLoggedIn which, in theory protects my endpoints. It goes like so:
function isLoggedIn(req, res, next) {
console.log("This is the authentication middleware, is req authenticated?");
console.log(req.isAuthenticated());
console.log("Does req.user exist?")
console.log(req.user);
return next();
}
Now, you would expect that because I called req.login and I got redirected to my endpoint of choice, the request would be authenticated. This is not the case.
Request Login supossedly successful.
This is the authentication middleware, is req authenticated?
false
Does req.user exist?
undefined
I can't seem to find the source of my problem. Everything checks out, as the strategy is being invoked, as well as the callback function and req.login which would render, in theory, a req.user object with data in it. One odd thing I've observed is that I don't see the passport.deserializeUser() method in action. Ever. But that could be tangential to the problem. Passport is definitely using my strategy and rendering a user object, but somehow this same object is not going into the request. Do you have any suggestion or idea about what is going on?
I solved the problem by juggling around with the tutorial I started with when I first learned how to use the Passport middleware. Turns out I was doing the configuring wrong: My code used to be like this in the server file:
pass = require("passport");
app.use(pass.initialize());
app.use(pass.session());
require("./app/config/passport.js")(pass);
when it should have been this:
pass = require("passport");
require("./app/config/passport.js")(pass);
app.use(pass.initialize());
app.use(pass.session());
Either I missed the part in the documentation where it's specified that configuration must come before initialization or it's simply written off as a trivial thing to remark. Either way, I solved my problem.
Make sure withCredentials: true while sending the post request.
// register
axios.post(uri, {
email: email,
password: password,
confirmPassword: confirmPassword
}, {
withCredentials: true
})

Google authentication: failed to serialize user into session

I'm trying to get some basic Google authentication going with PassportJS.
The amount of information on the web seems rather limited and I keep hitting issues so thought I would try here.
I am using the code from https://github.com/mattgaidica/twitter-mongo with a few modifications to use it for Google OAuth (it doesn't use the Twitter keys, it uses passport-google, passport.authenticate('google', ...)).
I keep ending up with this error: 'Error: failed to serialize user into session'
passport.serializeUser(function(user, done) {
console.log(user); //does not have the fields we created earlier, user.uid does not exist.
done(null, user.uid);
});
My Passport Strategy:
passport.use(new GoogleStrategy({
returnURL: "http://localhost:3000/auth/google/callback"
},
function(identifier, profile, done) {
User.findOne({uid: profile.id}, function(err, user) {
if(user) {
done(null, user);
} else {
var user = new User();
user.provider = "google";
user.uid = identifier;
user.name = profile.displayName;
user.save(function(err) {
if(err) { throw err; }
done(null, user);
});
}
})
}
));
The fields of this other user are not the same as the one originally created, what happened to the other user?
I'm a bit lost as to what is going on here, if anyone could let me know what I'm doing wrong I would be very grateful.
In your query, you use profile.id:
User.findOne({uid: profile.id}, function(err, user) { ... });
But that should be identifier.
Also, you're using the OpenID-version of the Passport Google plug-in, which is rather old (and doesn't even work properly on Node 0.10). I'd suggest you use passport-google-oauth instead.

Categories