← Back

Creating Secure Password Flows With Node.js And MySQL

By Vivek Singh
Picture of the author
Published on
Node.js

Creating secure password flows is crucial for any web application to protect user data and maintain trust. In this blog post, we'll walk through how to set up secure password flows using Node.js and MySQL. We'll cover user registration, password hashing, secure storage, and user authentication.

Prerequisites

Before we start, ensure you have the following installed:

  • Node.js and npm
  • MySQL
  • A code editor (like VSCode)

Setting Up the Project

Step 1: Initialize the Node.js Project

First, create a new directory for your project and initialize it with npm.

mkdir secure-password-flow
cd secure-password-flow
npm init -y

Step 2: Install Dependencies

We'll need several npm packages to build our application:

  • express: Web framework for Node.js
  • mysql2: MySQL client for Node.js
  • dotenv: Loads environment variables from a .env file
  • bcrypt: Library to hash and compare passwords
npm install express mysql2 dotenv bcrypt

Step 3: Set Up MySQL

Create a new MySQL database and a users table.

CREATE DATABASE secure_password_flow;
USE secure_password_flow;

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(255) NOT NULL,
  password VARCHAR(255) NOT NULL
);

Building the Application

Step 4: Set Up Environment Variables

Create a .env file in the root of your project to store your database credentials.

DB_HOST=localhost
DB_USER=root
DB_PASSWORD=your_password
DB_NAME=secure_password_flow

Step 5: Create the Database Connection

Create a file named db.js to handle the MySQL connection.

// db.js
const mysql = require('mysql2');
require('dotenv').config();

const connection = mysql.createConnection({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  password: process.env.DB_PASSWORD,
  database: process.env.DB_NAME,
});

connection.connect((err) => {
  if (err) {
    console.error('Error connecting to the database:', err.stack);
    return;
  }
  console.log('Connected to the database');
});

module.exports = connection;

Step 6: Set Up Express Server

Create a file named server.js to set up the Express server.

// server.js
const express = require('express');
const bodyParser = require('body-parser');
const bcrypt = require('bcrypt');
const connection = require('./db');

const app = express();
const port = 3000;

app.use(bodyParser.json());

app.listen(port, () => {
  console.log(`Server running on http://localhost:${port}`);
});

Step 7: Implement User Registration

In server.js, add a route to handle user registration.

// server.js
// ... previous code ...

app.post('/register', async (req, res) => {
  const { username, password } = req.body;

  if (!username || !password) {
    return res.status(400).send('Username and password are required');
  }

  try {
    const hashedPassword = await bcrypt.hash(password, 10);

    const query = 'INSERT INTO users (username, password) VALUES (?, ?)';
    connection.query(query, [username, hashedPassword], (err, results) => {
      if (err) {
        console.error('Error inserting user:', err.stack);
        return res.status(500).send('Error registering user');
      }
      res.status(201).send('User registered successfully');
    });
  } catch (error) {
    console.error('Error hashing password:', error);
    res.status(500).send('Internal server error');
  }
});

Step 8: Implement User Login

Add a route to handle user login.

// server.js
// ... previous code ...

app.post('/login', (req, res) => {
  const { username, password } = req.body;

  if (!username || !password) {
    return res.status(400).send('Username and password are required');
  }

  const query = 'SELECT * FROM users WHERE username = ?';
  connection.query(query, [username], async (err, results) => {
    if (err) {
      console.error('Error querying user:', err.stack);
      return res.status(500).send('Internal server error');
    }

    if (results.length === 0) {
      return res.status(400).send('Invalid username or password');
    }

    const user = results[0];

    try {
      const match = await bcrypt.compare(password, user.password);
      if (!match) {
        return res.status(400).send('Invalid username or password');
      }
      res.status(200).send('Login successful');
    } catch (error) {
      console.error('Error comparing passwords:', error);
      res.status(500).send('Internal server error');
    }
  });
});

Step 9: Test the Application

Start your server:

node server.js

Use tools like Postman or cURL to test the /register and /login endpoints.

Register a new user:

POST /register
Content-Type: application/json

{
  "username": "testuser",
  "password": "password123"
}

Login with the registered user:

POST /login
Content-Type: application/json

{
  "username": "testuser",
  "password": "password123"
}

Conclusion

By following these steps, you've created a secure password flow for user registration and login using Node.js and MySQL. Remember to always hash passwords before storing them and never store plaintext passwords. Additionally, continuously update your security practices to protect your users' data.

Happy coding!

Related Posts

Stay Tuned

Want to become a Full-Stack pro?
The best articles, links and news related to web development delivered once a week to your inbox.