kerolos aziz
kerolos aziz

Reputation: 1

Changing and hashing passwords with bcrypt

In my node.js app, I have a simple userSchema that allows users to login and all other basic crud operation for authentication. In my change password, where the problem is occurring, I am getting the right response but I cannot login with the new password.


const userSchema = new mongoose.Schema({
    username: {
        type: String,
        unique: true,
        required: [true, "Please enter a username"],
        trim: true,
        minlength: [3, "Minimum username length is 3 characters"],
        maxlength: [10, "Maximum username length is 10 characters"]
    },
    password: {
        type: String,
        trim: true,
        required: [true, "Must provide a password"],
        minlength: [6, "Minimum password length is 6 characters"]
    },
    email:{
        type: String,
        unique: true,
        required: [true, "Please enter an email"],
        validate: [isEmail, "Please enter a valid email"]
    },
    createdAt: {
        type: Date,
        default: Date.now
    }
});

userSchema.pre("save", async function(next) {
    if (this.isModified("password")) {
        const salt = await bcrypt.genSalt();
        this.password = await bcrypt.hash(this.password, salt);
    }
    next();
});
userSchema.statics.login = async function(username, password) {
    const user = await this.findOne({ username });
    if (user) {
        const auth = await bcrypt.compare(password, user.password);
        if (auth) {
            return user;
        }
        throw Error("incorrect password");
    }
    throw Error("incorrect username");
};
const login_post = async (req, res) => {
    const { username, password } = req.body;
    try {
        const user = await User.login(username, password);
        const token = createToken(user._id);
        res.cookie("jwt", token, {
            httpOnly: true,
            sessionLength: sessionLength * 1000
        });
        res.status(201).json({ user: user._id, message: token });
    } catch (error) {
        const errors = handleErrors(error);
        res.status(400).json({ errors });
    }
};

const changePassword = async (req, res) => {
    const { oldPassword, newPassword, confirmPassword } = req.body;
    try {
        const userId = req.user.id;
        const user = await User.findById(userId);

        if (!user) {
            return res.status(404).json({ message: "User not found" });
        }
        if (newPassword !== confirmPassword) {
            return res.status(400).json({ message: "Passwords do not match" });
        }
        const auth = await bcrypt.compare(oldPassword, user.password);
        if (!auth) {
            return res.status(400).json({ message: "Incorrect old password" });
        }
        const salt = await bcrypt.genSalt();
        const hashedNewPassword = await bcrypt.hash(newPassword, salt);
        user.password = hashedNewPassword;
        await user.save();
        res.status(200).json({ message: "Password updated successfully" });
    } catch (error) {
        res.status(400).json({ error: error.message });
    }
};

Scenario: I can create a user, log in, and logout. But if I change the password I can no longer login with that user. I am guessing somehow I am hashing my password differntly therfore they no longer match but the algorthim is the same. When I try to login again I get "Wrong password"

Upvotes: 0

Views: 81

Answers (2)

kerolos aziz
kerolos aziz

Reputation: 1

Turns out the userSchema.pre("save") was hashing my password becuase the password field was modified and my my change password was also hashing it. Removing the hashing from my change password controller fixed my issue

Upvotes: 0

user26341567
user26341567

Reputation: 69

This issue is due to the fact that you use the built-in genSalt() function, and perhaps the await keyword. If you specify an integer rather than use this function, you'll be able to log in successfully even if you change your password later.

For instance, you can use the following code snippet for the password creation or altering process:

const salt = 12; // Or greater for security considerations...
bcrypt.hash(password, salt, (err, hashedPassword) => {
    if (!err && hashedPassword) console.log(hashedPassword);
    else throw err;
});

Here's one more code, which I have written for you:

const express = require("express");
const mysql = require("mysql2");
const bcrypt = require("bcrypt");

process.on("uncaughtException", (err) => console.error(err.stack));

const app = express();

app.use(express.json());

app.post("/api/create", async (req, res) => {
    const { password } = req.body;
    bcrypt.hash(password, 12, (error, hashedPassword) => {
        if (!error && hashedPassword) {
            db.query("INSERT INTO passwords (password) VALUES (?)", [hashedPassword], (err, results) => {
                if (!err) res.status(201).json({ success: true });
                else res.status(500).json({ success: false });
            });
        } else res.status(500).json({ success: false });
    });
});

app.post("/api/log-in", async (req, res) => {
    const { password } = req.body;
    db.query("SELECT password FROM passwords", [], (err, results) => {
        if (!err && results.length > 0) {
            bcrypt.compare(password, results[0].password, (error, isMatch) => {
                if (!error && isMatch) res.status(200).json({ success: true });
                else res.status(401).json({ success: false });
            });
        } else res.status(404).json({ success: false });
    });
});

app.post("/api/change-password", async (req, res) => {
    const { new_password } = req.body;
    bcrypt.hash(new_password, 12, (error, hashedPassword) => {
        if (!error && hashedPassword) {
            db.query("UPDATE passwords SET password = ?", [hashedPassword], (err, results) => {
                if (!err) res.status(200).json({ success: true });
                else res.status(500).json({ success: false });
            });
        } else res.status(500).json({ success: false });
    });
});

app.listen(3000, "192.168.1.7", () => console.log("HTTP server is running..."));

const db = mysql.createPool({
    host: "192.168.1.7",
    port: 3306,
    database: "password",
    user: "root",
    password: ""
});

db.getConnection((err) => {
    if (!err) console.log("MySQL database connection is successful!");
    else throw err;
});

Upvotes: 0

Related Questions