I am stumped trying to get my passwords to successfully compare with bcrypt using node. Maybe I missed something, but on account creation, I do the following within the signup method (with some code abbreviated):
bcrypt.genSalt(10, function(err, salt) {
if(err) {
}
bcrypt.hash(user.Password, salt, function(err, hash) {
console.log('hashing and saving');
db.query(db insert code, function (error, rows, fields) {
if(error) {
console.log(error);
res.setHeader('500', { 'Content-Type': 'x-application/json'});
res.send({UserId: 0, ErrorMessage: 'Something terrible happened.'});
} else {
console.log('User created : ' + rows.insertId);
res.setHeader('200', { 'Content-Type': 'x-application/json'});
res.send({UserId: rows.insertId});
}
});
});
});
return next();
This all works fine. My db has the encrypted password. But when a user signs in, I cannot get a successful result from bcrypt.compare:
db.query(get account code, function(error, rows, fields) {
if(rows.length == 1) {
bcrypt.compare(request.params.password, rows[0].Password, function(err,res) {
if(err) { console.log(err.toString()); }
if(res == true)
{
response.setHeader('200', { 'Content-Type': 'x-application/json' });
response.send({result: true});
} else {
response.setHeader('401', { 'Content-Type': 'x-application/json' });
console.log('invalid password');
response.send({result:false});
}
});
}
});
return next();
And I always end up with invalid password. Do I need to take the cleartext password and re-encrypt it before comparing to what I pull out of the database?
you can skip doing bcrypt.genSalt and use bcrypt.hash(password, 10, function(err, hash) {..});
your compare function seems good to me.
this is working fine for me:
var bcrypt = require('bcrypt');
bcrypt.hash('mypassword', 10, function(err, hash) {
if (err) { throw (err); }
bcrypt.compare('mypassword', hash, function(err, result) {
if (err) { throw (err); }
console.log(result);
});
});
I dont know if you have the same as I did, I had the same problem because my table had the length of 45 chars and bcrypt compares if the hash lenght is diferent from 60 it returns false. Just increase the length of characters in your table
Arguments for bcrypt's compare method should be
bcrypt.compare(actual_password, encrypted_password)
instead of
bcrypt.compare(encrypted_password, actual_password)
=> the encrypted_password should be the second argument.
Mine was due to my database column not having a large enough varchar length. A good place to check.
For me it was just an arguments disorder
The right order
bcrypt.compare(plainPasswordToCheck, hashedPasswordOnStorage)
I had the same problem. After changing the node package from bcrypt to bcryptjs the comparision worked like a charm. Since the package seems to be a fork, the functions do not need to be adjusted.
I had this same problem, but I am sure I am not encoding my password twice. Here is the thing.
bcrypt-nodejs npm package is on v0.0.3 and I am using this version. I am writing the algorithm to store a user password on register and read a user password on login.
The frontend is a simple with input text for email field and input password for password field. When I submit the request I POST a call to https://localhost... on my local node server. I can log the data received and I can see the password logged is the same as the password inserted on frontend.
The code used to store the password is:
//var user.bcrypt = bcrypt.genSaltSync(10);;
var clearPwd = user.password;
user.password = bcrypt.hashSync(clearPwd);//, user.bcrypt);
log4.debug("hashSyncked: "+ user.password);
db.userSave(user, cb);
The code used to read and compare password is:
log4.debug('compare '+pwd+' with saved on db for user %j', userDoc.password);
var okPwd = bcrypt.compareSync(pwd, userDoc.password);
So, I see the hashed password, it is logged as a string like $ert3435tF.02ri etc...
But everytime I login with the same password I registered with, okPwd is always false. Why?
Even if I un-comment the commented code!
UPDATE
The solution I found was about methods. Password should not be stored and read like that, it is too ...rude !! The correct method is mentioned here Watch out! There is an error in that guideline. bcrypt.hash(...) functions needs 2 object parameter and 2 callbacks! The last one is the one called at the end of the hash process, the first is called to track the hash proces. I put that a null and it all works well.
I admit I made another mistake: I used bcrypt-nodejs package instead of brcrypt.
Just modify the length of characters in your database assign to password field, maybe the hash generated is more larger than the field can support
my hash was starting with $2y and it had to start with $2b
This library supports $2a$ and $2b$ prefix bcrypt hashes. $2x$ and
$2y$ hashes are specific to bcrypt implementation developed for John
the Ripper. In theory, they should be compatible with $2b$ prefix.
Very easy to mix up the order in the compare function ;)
bcrypt.compare(user_entered_password, database_encrypted_password)
i dont know if you have the same as I did, I had the same problem because my table had the length of 35 chars and bcrypt compares if the hash lenght is diferent from 60 it returns false. Just increase the length of characters in your table
This works for me.
var bcrypt = require('bcrypt');
var salt = bcrypt.genSaltSync();
bcrypt.hash('mypassword', salt, function(err, hash){
if(err) throw err;
bcrypt.compare('mypassword', hash, function(err, result) {
if (err) { throw (err); }
console.log(result);
});
});
I had the same issue and for me the solution was to fix a typo in my frontend. I was sending 'pasword' from my form and expecting 'password'. Somehow bcyppt then hashed the returned undefined value and that was the reason compare() always returned false.
Hope this helps someone!
Another possible solution which worked for me is if in your User model you put under password field.
lowercase: true,
I happened to had this one copied from another field. When I removed it the issue disappeared.
In the compare function, you do not need to generate a new hash, do this:
async function Login(email, password) {
const user = await this.service.getByEmail(email);
const passwordBd = user.user_password;
const matching = await bcrypt.compare(password, passwordBd);
console.log(matching); //true
};
I deleted my user and recreated it and did this
const isMatch = await bcrypt.compare(password, user.password);
console.log(user.password, isMatch);
if (!isMatch) {
return res.status(400).json({
msg:
"Sorry, your password was incorrect. Please double-check your password.",
});
and at the time of creating a user, I did this
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(password, salt);
In my case, I was passing in the hash as a command line argument to a node program - just for testing:
node admin/bcrypt.js password $2b$10$/v9nAxpPQoDH5LMa/q.0AON/gEk.AxF57hHtIGkKR5IAWfMLyBcmm
The hash started with $2b$10$/; the $2 and $1 were interpreted as positional arguments and evaluated to empty values, hence the value being compared was different than what I passed in. Escaping the $ symbols with a \ solved the issue:
node admin/bcrypt.js password \$2b\$10\$/v9nAxpPQoDH5LMa/q.0AON/gEk.AxF57hHtIGkKR5IAWfMLyBcmm
I had the same problem with postgresql, but should always be the same.
I simply had to trim my db result:
bcrypt.compare(
req.body.password,
String(user.PASSWORD).trim()
)
In my case, the problem was that in schema type option for password, i set lowercase to true...after removing lowercase set to true for my password schema type option and dropping the collection using compass and recreating the collection, bcrypt is working fine....
That was due to password length 45, increase it and that solves the issue.
Related
I'm building an API that I intend to use with my react native application. The problem which I'm facing right now is that I when I try to hit this particular route /api/auth/signup in Postman I get the Could not get any response error message.
This is the route:
//create user token
router.post(
"/signup",
[check("username").isEmail(), check("password").isLength({ min: 6 })],
async (req, res) => {
//validate input field on the backend
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
const { username, password, firstName, lastName } = req.body;
try {
//search DB if there is an existing user
let user = await User.findOne({ username });
if (user) {
return res.status(400).json({ msg: "User already exists" });
}
const salt = await bcrypt.genSalt(10);
res.status(200).json({ data: salt });
} catch (error) {}
}
);
module.exports = router;
The strange thing is that if I remove the User.findOne function I get a response. I don't know why this keeps happening, as I had built a similar application following the same pattern without a problem.
NOTE: In the main app.js I have the app.use(express.json({extended:true}), I've also successfully linked the routes in the main file too. Any help would be greatly appreciated!
I think you have a typo in your app.use... statement which you've given in your comment as,
app.use(express.json({extented:true})
which needs to be corrected as, ('d' should come in place of 't')
app.use(express.json({extended:true})
Hope this helps!
So it turns out when I was requiring mongoose in one of my models I required it with an uppercase letter const mongoose = require('Mongoose') which isn't valid, therefore the findOne method won't run because there's no model to take it from. Strange that visual studio code didn't complain about the false import. Anyways, thanks to anyone willing to help me out :) !
I wrote this code to check if an email already exists in the database:
async store (req,res) {
const email = req.body.email;
let user = await User.findOne ({ email: email });
if (user) {
console.log('Already exist.')
};
(...)
}
But it's not working: I can store the info in the User collection but it's email is not verified.
I'm using Mongoose.
What I'm doing wrong?
You need to use exec() at the end to actually run the query:
let user = await User.findOne({ email: email }).exec();
Also, since you're using await, make sure the containing function is marked async.
I am limited in the information I can give you because you just say "It's not working". That doesn't tell me anything. Do you run it and nothing happens? Does it give you an error? People on this site don't like to hear the words: "it's not working".
You haven't described your use case, but if you're looking to avoid email collisions, using mongoose, when you define the object's schema, you can use the unique: true option. It will then reject any new or updated User that submits an already stored email.
I am trying to create a very simple registration method on my project but I am having trouble figuring out how to stop postgres from adding in people with the same email. I am using postgres and Node.js.
I have an add function that I want to return false my postgres table already has a user with the email he/she tried using. I do the following:
function checkExistingEmail(email, cb){
pg.connect(cstr, function(err, client, done){
if(err){
cb(err);
}
else{
var str = 'SELECT email from Swappers where email=$3';
client.query(str, function(err, result){
if(err){
cb(err);
}
else{
console.log(result.row.email);
if(result.row.email === undefined){
cb(false);
}
else{
cb(true);
}
}
});
}
});
}
Now when I display result.row.email to the console I get that it is undefined. Which is what I want for the first time user, so it should return true, and I should be able to add the user to the database and move on. But that is not the case.
In a file I have called users.js I have the following route handler:
router.post('/authnewuser', function(req,res){
// Grab any messages being sent to use from redirect.
var authmessage = req.flash('auth') || '';
var name = req.body.username;
var password = req.body.password;
var email = req.body.email;
db.checkExistingEmail(email, function(data){
if(data === true)
console.log('success');
else
console.log('fail');
});
});
Now When I run this and try registering the functionality I want is not working. I was wondering if is has to go with my checkExistingEmail function and if I am using results.row.email correctly. Right now When I run this code I just keep getting that it has failed. Which is not what I want. it should be returning true for a new user with an email that has never been saved into the db before.
This is usually not the way to go with a database. Checking first always requires two round-trips to the database. Instead,
put a unique constraint on the "email" column,
just insert the data, and
handle the error you'll get with a duplicate email.
Most inserts will just succeed--one round-trip to the database. And you have to handle errors anyway--there's a lot of reasons an INSERT can fail. So there's not a lot of additional code to write for this specific error.
I'm using Express JS and Passport JS for my app.
I want to give a new user the opportunity to automatically login, once, by a specific URL. I can get the user from the database with the information from the URL, so I have an User object (with id, email, hashed password etc.) but I don't know how I can use passport to authenticate the user and login.
I tried executing below function with the user object I got from the database:
req.login(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + req.user.username);
});
source: http://passportjs.org/guide/login/
But that didn't work. Guess it's just because the user object contains the hashed password...
Anyone who ever tried this before and can tell me how it works?
Maybe https://github.com/yarax/passport-url strategy will be useful for you
Base logic is getting argument from url
UrlStrategy.prototype.authenticate = function(req, options) {
var self = this;
function verified(err, user, info) {
if (err) { return self.redirect(self.failRedirect); } // redirect in fail
self.success(user, info); // done callback
}
this._verify(req.query[this.varName], verified);
};
Full example here https://github.com/yarax/passport-url/blob/master/index.js
Heyo, so while #Rax Wunter is totally right, I just saw this question and wanted to say it is NOT A GOOD IDEA to do what you're doing here. You should never be passing a hashed password in a URL string ever. This is a really bad security concern.
What you should do instead is use something like a JSON Web Token (JWT). There are lots of libraries to help with this, but the basic flow goes something like this:
Wherever you are generating your URL, you'll instead generate a JWT that contains the user ID in it.
You'll then build a URL that looks like: https://somesite.com/?token=
On your https://somesite.com endpoint, you'll read in the token, validate it using the JWT library (and a shared secret variable), and this will confirm this token was unmodified (eg: you KNOW this user is who they claim to be).
This strategy above is really great because it means you can safely log someone in, in a trusted way, without compromising security or leaking a password hash at all.
There is not need of any additional module or passport-strategy for this. Adjust below code according to your use case;
router.get('/url/:token', (req, res) => {
User.findOne({token: req.params.token}, (err, user) => {
req.login(user, {}, function(err) {
if (err) { console.error(err); }
else return res.redirect("/home.html");
});
});
});
I'm writing my first (non tutorial) node application and am at a point where I'm writing a function that should take the username and password as parameters and query them against the user table of my database to return either true or false. The database is setup, and the app is connecting to it successfully.
However, I haven't worked with SQL very much, nor node, and I'm unsure how to proceed with this function (and short surrounding script). Here it is:
console.log('validator module initialized');
var login = require("./db_connect");
function validate(username, password){
connection.connect();
console.log('Connection with the officeball MySQL database openned...');
connection.query(' //SQL query ', function(err, rows, fields) {
//code to execute
});
connection.end();
console.log('...Connection with the officeball MySQL database closed.');
if(){ //not exactly sure how this should be set up
return true;
}
else{ //not exactly sure how this should be set up
return false;
}
}
exports.validate = validate;
This is using node-mysql. I'm looking for a basic example of how I might set the query and validation up.
I think you'll want to rethink your app into a more node-like way (i.e. one that recognizes that many/most things happen asynchronously, so you're not usually "returning" from a function like this, but doing a callback from it. Not sure what you plan to get from node-mysql, but I would probably just use the plain mysql module. The following code is still most likely not entirely what you want, but will hopefully get you thinking about it correctly.
Note that the use of 'return' below is not actually returning a result (the callback itself should not return anything, and thus its like returning undefined. The return statements are there so you exit the function, which saves a lot of tedious if/else blocks.
Hope this helps, but I'd suggest looking at various node projects on github to get a better feel for the asynchronous nature of writing for node.
function validate(username, password, callback){
var connection = mysql.createConnection({ user:'foo',
password: 'bar',
database: 'test',
host:'127.0.0.1'});
connection.connect(function (err){
if (err) return callback(new Error('Failed to connect'), null);
// if no error, you can do things now.
connection.query('select username,password from usertable where username=?',
username,
function(err,rows,fields) {
// we are done with the connection at this point), so can close it
connection.end();
// here is where you process results
if (err)
return callback(new Error ('Error while performing query'), null);
if (rows.length !== 1)
return callback(new Error ('Failed to find exactly one user'), null);
// test the password you provided against the one in the DB.
// note this is terrible practice - you should not store in the
// passwords in the clear, obviously. You should store a hash,
// but this is trying to get you on the right general path
if (rows[0].password === password) {
// you would probably want a more useful callback result than
// just returning the username, but again - an example
return callback(null, rows[0].username);
} else {
return callback(new Error ('Bad Password'), null);
}
});
});
};