DEV Community

Cover image for Building a Secure Password Reset System with Node.js and MySQL
Shreyansi Shrestha
Shreyansi Shrestha

Posted on

Building a Secure Password Reset System with Node.js and MySQL

In this guide, we'll walk through implementing a password reset feature using Node.js, Express, MySQL, and bcrypt. This will ensure users can securely reset their passwords through an email token-based system.

1. Setting Up the Node.js Project

Start by installing the required dependencies:

npm install express mysql bcrypt ejs body-parser
Enter fullscreen mode Exit fullscreen mode

express – Framework for handling HTTP requests
mysql – To interact with MySQL database
bcrypt – For hashing passwords securely
ejs – To render views
body-parser – To parse form data

Next, create an index.js file and set up the server:

const express = require('express');
const mysql = require('mysql');
const bcrypt = require('bcrypt');
const bodyParser = require('body-parser');

const app = express();
app.use(bodyParser.urlencoded({ extended: true }));

const db = mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: '',
    database: 'mydb'
});

db.connect(err => {
    if (err) throw err;
    console.log('Connected to MySQL');
});
Enter fullscreen mode Exit fullscreen mode

2. Validating the Reset Token

When a user clicks the "Forgot Password" link, they receive a token via email. The API must verify that token before allowing a password reset.

const resetPasswordLoad = (req, res) => {
    const token = req.query.token;
    if (!token) return res.render('404');

    db.query('SELECT * FROM password_resets WHERE token=? LIMIT 1', [token], (err, result) => {
        if (err || result.length === 0) return res.render('404');

        db.query('SELECT * FROM users WHERE email=? LIMIT 1', [result[0].email], (err, user) => {
            if (err) return res.render('404');
            res.render('reset-password', { user: user[0] });
        });
    });
};


Enter fullscreen mode Exit fullscreen mode
  • Retrieves the token from the URL
  • Checks if it exists in the password_resets table
  • If valid, fetches the corresponding user and renders the password reset form

3. Creating the Reset Password Form

Create views/reset-password.ejs:

<form action="/https/dev.to/reset-password" method="POST">
    <input type="hidden" name="email" value="<%= user.email %>" />
    <label>New Password:</label>
    <input type="password" name="password" required />
    <button type="submit">Reset Password</button>
</form>
Enter fullscreen mode Exit fullscreen mode

4. Updating the Password in MySQL

Handle the password update in index.js:

app.post('/reset-password', (req, res) => {
    const { email, password } = req.body;

    if (!password) {
        return res.render('message', { message: 'Password cannot be empty!' });
    }

    const hashedPassword = bcrypt.hashSync(password, 10);

    db.query('UPDATE users SET password=? WHERE email=?', [hashedPassword, email], (err) => {
        if (err) return res.render('message', { message: 'Error updating password.' });

        db.query('DELETE FROM password_resets WHERE email=?', [email], () => {
            res.render('message', { message: 'Password reset successful! You can now log in.' });
        });
    });
});

Enter fullscreen mode Exit fullscreen mode
  • Hashes the new password before updating it
  • Deletes the password reset token after a successful reset

5. Displaying Success/Error Messages

Create views/message.ejs:

<% if (message) { %>
    <h2><%= message %></h2>
<% } %>
Enter fullscreen mode Exit fullscreen mode

6. Running the Server

Start the Node.js server:

node index.js
Enter fullscreen mode Exit fullscreen mode

Now, the password reset system is functional!

While working on the password reset system in Node.js and MySQL, I wanted to ensure both security and efficiency. Using verification tokens added a layer of authentication, while hashed passwords protected user data. Additionally, implementing proper validation helped prevent errors and improve reliability. This approach made the system more robust and user-friendly.

Top comments (0)