This is the standard working version of auth0 custom database login connection with MONGODB,
function login(email, password, callback) {
const bcrypt = require('bcrypt');
const MongoClient = require('mongodb#3.1.4').MongoClient;
const client = new MongoClient('mongodb+srv://user:'+configuration.MONGO_PASSWORD+'#cluster0-2uci2.mongodb.net/?retryWrites=true&w=majority');
client.connect(function (err) {
if (err) return callback(err);
const db = client.db('db-name');
const users = db.collection('users');
users.findOne({ email: email }, function (err, user) {
if (err || !user) {
client.close();
return callback(err || new WrongUsernameOrPasswordError(email));
}
bcrypt.compare(password, user.password, function (err, isValid) {
client.close();
if (err || !isValid) return callback(err || new WrongUsernameOrPasswordError(email));
return callback(null, {
user_id: user._id.toString(),
nickname: user.nickname,
email: user.email
});
});
});
});
}
I am attempting to edit this to check against the username field as well as shown below,
function login(email, username, password, callback) {
const bcrypt = require('bcrypt');
const MongoClient = require('mongodb#3.1.4').MongoClient;
const client = new MongoClient('mongodb+srv://user:'+configuration.MONGO_PASSWORD+'#cluster0-2uci2.mongodb.net/?retryWrites=true&w=majority');
client.connect(function (err) {
if (err) return callback(err);
const db = client.db('test');
const users = db.collection('users');
users.findOne({$or: [ {email: email }, {username: username }] }, function (err, user) {
if (err || !user) {
client.close();
return callback(err || new WrongUsernameOrPasswordError(email));
}
bcrypt.compare(password, user.password, function (err, isValid) {
client.close();
if (err || !isValid) return callback(err || new WrongUsernameOrPasswordError(email));
return callback(null, {
user_id: user._id.toString(),
nickname: user.nickname,
email: user.email
});
});
});
});
}
However I get a callback is not a function error. I am relatively new to javascript so I am not sure if I am able to edit the code the way I did, could someone please help? Thank you in advance!
Related
This is my passport-config.js file. It should show the user can be serialised but for some reason it is not working.
const LocalStrategy = require('passport-local').Strategy
const { pool } = require("./db-config");
const bcrypt = require('bcrypt')
function initialize(passport, getUserById) {
const authenticateUser = async (email, password, done) => {
console.log(email, password);
pool.query(
`SELECT * FROM users WHERE email = $1;`,
[email],
(err, results) => {
if (err) {
throw err;
}
console.log(results.rows);
if (results.rows.length > 0) {
const user = results.rows[0];
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) {
console.log(err);
}
if (isMatch) {
return done(null, user);
} else {
//password is incorrect
return done(null, false, { message: "Password is incorrect" });
}
});
} else {
// No user
return done(null, false, {
message: "No user with that email address"
});
}
}
);
};
passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
return done(null, getUserById(id))
})
}
module.exports = initialize
I think it's something to do with the PSQL query and it not recognising the user id. Please help :)
I have used bcryptjs to hash my passwords and the registration of the user takes place fine.
But when I try to login, the bcrypt.compare function returns a false promise if the passwords contain numbers or other characters.
Everything works fine if the password is just letters.
I have searched everywhere but could not find a solution for this error?
Here are my files :
users.js (MODEL)
var mongoose = require("mongoose");
var bcrypt = require("bcryptjs");
var userSchema = mongoose.Schema({
name: String,
email: String,
password: String,
products: [{
type: mongoose.Schema.Types.ObjectID,
ref: "Product"
}],
username: String
});
var User = module.exports = mongoose.model("User", userSchema);
module.exports.createUser = function(newUser, callback) {
bcrypt.genSalt(5,function(err,salt){
bcrypt.hash(newUser.password,salt,function(err,hash){
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
if(err) throw err;
console.log(isMatch);
callback(null, isMatch);
});
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
app.js
app.use(passport.initialize());
app.use(passport.session());
var LocalStrategy = require("passport-local").Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({username: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) {
console.log("ERR1");
return done(err);
}
if(isMatch) {
console.log("MATCH");
return done(null,user);
} else {
console.log("NOT VALID");
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);
})
})
users.js (ROUTE)
router.post("/login", passport.authenticate('local', function (error, user, info){
if(error) {
console.error(error);
console.log('Failed login:');
}
if (user === false) {
console.log("user not found");
} else {
// handle successful login ...
console.log("logged in");
}
}), function (req, res) {
res.send(req.user);
});
router.post("/signup", function (req, res) {
console.log(req.body);
var password = req.body.password;
var password2 = req.body.password2;
if(password == password2) {
var newUser = new User ({
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.username
});
User.createUser(newUser, function(err, user){
if(err)
throw err;
console.log(user);
res.send(user).end();
});
} else {
res.status(500).send("{errors: \"Passwords don't match\"}").end()
}
});
Whenever I enter a password that contains numbers, I get
false
NOT VALID
user not found
I'm sorry if I have done or not done something extremely simple. This is my first time using bcryptjs.
All answers are appreciated!
In the users.js file at the comparePassword function inside the compare method of bcrypt you are throwing the error instead of passing it to the callback. Maybe if you make this change:
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch) {
console.log(isMatch);
callback(err, isMatch);
});
}
You will see what kind of error it's generated by the case when you introduce numbers in your passwords.
I 'm having a problem with the compare function in b crypt, I have a salt password I can not get it to compare password to the encrypted password in the database here is my code...
router.post('/login', (req, res) => {
let userName = req.body.userName;
let password = req.body.password;
connection.query(
SELECT_ALL_USERS_QUERY + ' WHERE userName=?',
[userName],
(err, results, fields) => {
if (results[0].password) {
bcrypt.compare(password, results[0].password, (err, result) => {
console.log(password);
console.log(results[0].password);
if (result) {
res.send();
} else {
return res.status(400).send();
}
});
}
}
);
});
router.post('/add', (req, res) => {
const {
firstName = req.body.firstName,
lastName = req.body.lastName,
userName = req.body.userName,
password = req.body.password,
email = req.body.email
} = req.query;
const salt = 16;
bcrypt.hash(password, salt, (err, hashPass) => {
if (err) throw err;
const INSERT_USERS_QUERY =
'INSERT INTO users (' +
'firstName, lastName, userName, password, email) values(' +
`'${firstName}','${lastName}','${userName}','${hashPass}','${email}')`;
connection.query(INSERT_USERS_QUERY, (err, results) => {
if (err) {
return res.send(err);
} else {
return res.send('Successfuly added user');
}
});
});
});
can anyone help me..
So I'm trying to build a very basic user login. I'm trying to create a user, then login with those credentials and get back a JSON Web Token. Where I'm stuck is trying to compare the passwords then send a response.
Steps:
Create User:
enter email and password
salt/hash user password
store user into database
return success
Login
find user by request email value
if found compare passwords
passwords good send JSON Web Token
User Model
email:{
type: String,
required: true,
unique: true
},
password: {
type: String,
required: true
}
User Routes
var express = require('express');
var router = express.Router();
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
// Create User
...
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash("superSecret", salt, function(err, hash) {
user.password = hash;
user.save();
res.json({success: true, message: 'Create user successful'});
});
});
...
// Login
...
bcrypt.compare(req.body.password, 'superSecret', function(err, res) {
if(req.body.password != user.password){
res.json({success: false, message: 'passwords do not match'});
} else {
// Send JWT
}
});
So the two problems here is that, I can't send a response nor can I compare the password. Just completely stuck on this, any help would be greatly appreciated.
As described in the doc, you should use bcrypt.compare like that:
bcrypt.compare(req.body.password, user.password, function(err, res) {
if (err){
// handle error
}
if (res) {
// Send JWT
} else {
// response is OutgoingMessage object that server response http request
return response.json({success: false, message: 'passwords do not match'});
}
});
And here is a nice post about Password Authentication with Mongoose (Part 1): bcrypt
//required files
const express = require('express')
const router = express.Router();
//bcryptjs
const bcrypt = require('bcryptjs')
//User modal of mongoDB
const User = require('../../models/User')
//Post request for login
router.post('/', (req, res) => {
//email and password
const email = req.body.email
const password = req.body.password
//find user exist or not
User.findOne({ email })
.then(user => {
//if user not exist than return status 400
if (!user) return res.status(400).json({ msg: "User not exist" })
//if user exist than compare password
//password comes from the user
//user.password comes from the database
bcrypt.compare(password, user.password, (err, data) => {
//if error than throw error
if (err) throw err
//if both match than you can do anything
if (data) {
return res.status(200).json({ msg: "Login success" })
} else {
return res.status(401).json({ msg: "Invalid credencial" })
}
})
})
})
module.exports = router
If we you to use bcryptjs in browser(HTML) then you can add bcryptjs CDN to do this.
CDN - https://cdn.jsdelivr.net/npm/bcryptjs#2.4.3/dist/bcrypt.js
Example-
HTML- (Add above CDN in tag)
JS-
var bcrypt = dcodeIO.bcrypt;
/** One way, can't decrypt but can compare */
var salt = bcrypt.genSaltSync(10);
/** Encrypt password */
bcrypt.hash('anypassword', salt, (err, res) => {
console.log('hash', res)
hash = res
compare(hash)
});
/** Compare stored password with new encrypted password */
function compare(encrypted) {
bcrypt.compare('aboveusedpassword', encrypted, (err, res) => {
// res == true or res == false
console.log('Compared result', res, hash)
})
}
If you want to do same in Nodejs
/** Import lib like below and use same functions as written above */
var bcrypt = require('bcryptjs')
From what I can see your logic is correct.
If you are using mongoose I suggest you to use the pre 'save' hook.
User Schema
userSchema.pre('save', function(next) {
// only hash the password if it has been modified (or is new)
if (!this.isModified('password')) {
return next();
}
// generate a salt
return bcrypt.genSalt(10, function(error, salt) {
if (error) {
return next(error);
}
// hash the password using the new salt
return bcrypt.hash(this.password, salt, function(error, hash) {
if (error) {
return next(error);
}
// override the cleartext password with the hashed one
this.password = hash;
return next();
});
});
});
userSchema.methods.comparePassword = function(passw, cb) {
bcrypt.compare(passw, this.password, function(err, isMatch) {
if (err) {
return cb(err, false);
}
return cb(null, isMatch);
});
};
And in your routes:
Login
...
return user.comparePassword(password, function(error, isMatch) {
var payload = {
iat: Math.round(Date.now() / 1000),
exp: Math.round((Date.now() / 1000) + 30 * 24 * 60),
iss: 'Whatever the issuer is example: localhost:3000',
email: user.email
};
var token = jwt.encode(payload, 'secret');
if (isMatch && !error) {
// if user is found and password is right create a token
return res.json({
success: true,
token: `JWT ${token}`,
user: user,
msg: 'Authentication was succesful'
});
}
return next({code: 401, msg: 'Password is incorrect'});
});
});
Create user
// Pre hook will take care of password creation
return user.save()
.then(function(user) {
var payload = {
iat: Math.round(Date.now() / 1000),
exp: Math.round((Date.now() / 1000) + 30 * 24 * 60),
iss: 'Whatever the issuer is example: localhost:3000',
email: user.email
};
var token = jwt.encode(payload, 'secret');
return res.status(201).json({user, token: `JWT ${token}`, msg: 'User was succesfully created'});
})
.catch((err) => next(err));
bcrypt.compare(req.body.password, user.password, function(err, results){
if(err){
throw new Error(err)
}
if (results) {
return res.status(200).json({ msg: "Login success" })
} else {
return res.status(401).json({ msg: "Invalid credencial" })
}
})
const bcrypt = require("bcryptjs");
const salt = bcrypt.genSaltSync(10);
const hashPassword = (password) => bcrypt.hashSync(password, salt);
const comparePassword = (password, hashedPassword) =>
bcrypt.compareSync(password, hashedPassword);
bcrypt.compare(req.body.password, user.password)
.then(valid => {
if (!valid) {
return res.status(401).json({ message: 'Paire login/mot de passe incorrecte' });
}
res.status(200).json({
userId: user._id,
token:jwt.sign(
{userId: user._id},
process.env.ACCESS_TOKEN_SECRET_KEY,
{expiresIn:'24h'}
),
message: 'connected'
});
})
.catch(error => res.status(500).json({ error }));
enter code here
I'm trying to validate username before save it to mongodb. But instead saving or validation message i see the following message in terminal:
" if(user.path(username)){
TypeError: user.path is not a function"
What does it means?
I am newbie.
Here is my user.js
var User = require('models/user').User;
var HttpError = require('error').HttpError;
var async = require('async');
exports.get = function(req, res) {
res.render('login', { title: 'Login'});
};
exports.post = function(req, res, next) {
var username = req.body.username;
var password = req.body.password;
async.waterfall([
function(callback) {
User.findOne({username: username}, callback);
},
function(user, callback) {
if (user) {
if (user.checkPassword(password)) {
callback(null, user);
} else {
next(new HttpError(403, "wrong password"));
}
} else {
var user = new User({username: username, password: password});
if(user.path(username)){
callback(null, user);
user.save(function(err) {
console.log(err.message)
if (err)
return next(err);
callback(user);
});
}else{ next(new HttpError(403, "Incorrect username"));
};
}
}
], function(err, user){
if (err) return next(err);
req.session.user = user._id;
res.send({});
});
and here is my login.js
var crypto = require('crypto');
var mongoose = require('lib/mongoose'),
Schema = mongoose.Schema;
var schema = new Schema({
username: {
type: String,
unique: true,
required: true
},
hashedPassword: {
type: String,
required: true
},
salt: {
type: String,
required: true
},
created: {
type: Date,
default: Date.now
}
});
schema.path('username').validate(function (value, respond) {
return /[0-9]{6,15}[a-zA-Z]/.test(value, function(){
respond(false, 'this message gets to the validation error');
});
}, '{VALUE} is not a valid login - [0-9]{6,15}[a-zA-Z]')
schema.methods.encryptPassword = function(password) {
return crypto.createHmac('sha1', this.salt).update(password).digest('hex');
};
schema.virtual('password')
.set(function(password) {
this._plainPassword = password;
this.salt = Math.random() + '';
this.hashedPassword = this.encryptPassword(password);
})
.get(function() { return this._plainPassword; });
schema.methods.checkPassword = function(password) {
return this.encryptPassword(password) === this.hashedPassword;
};
schema.path('username').validate(function (value) {
return /[0-9]{6,15}[a-zA-Z]/.test(value);
}, 'Invalid color');
exports.User = mongoose.model('User', schema);
You don't need to call anything before saving to vaildate, mongoose will do it for you. Also don't call callback until you are done.
Also check if error occur before doing console.log(err.message) because err is null if now error happens.
So this should work:
} else {
var user = new User({username: username, password: password});
user.save(function(err) {
if (err) {
console.log(err.message);
return next(err);
}
callback(user);
});
}