How to Use Node.js BcryptJS Module With TypeScript

Posted December 21, 2023
How to Use Node.js BcryptJS Module With TypeScript

Have you tried using the Node.js BcryptJS module with TypeScript? BcryptJS hashes password values and avoids storing them in plaintext. This practice enhances password security.

In this tutorial, I will teach you how to perfectly use Node.js with the BcryptJS module alongside TypeScript to hash passwords with added TypeScript type safety.

Along this guide you will learn:

  • TypeScript Configuration with BcryptJS.
  • How to use TypeScript and compare the hashed password with the plain text password.
  • Create an example user registration authentication API using Express.js, TypeScript, and BcryptJS while adding Hash to new users.
  • How to use BcryptJS to log in users and compare user login plain password and system hashed password.

Related: Setup and Build a Vanilla TypeScript API with Node.js

Setting up a Node.js BcryptJS Module with TypeScript

BcryptJS stores passwords as hashed instead of plaintext. To use it with Node.js alongside with TypeScript, we will first create a TypeScript Node.js app as follows:

Step 1: Create a working directory and cd to it:

mkdir bcrypt-ts
cd bcrypt-ts

Step 2: Install TypeScript globally on your computer

npm i typescript -g

Step 3: Initialize Node.js in your bcrypt-ts directory with the package.json file:

npm init -y

Step 4: Now use TypeScript to initialize TypeScript and autogenerate TypeScript Node.js configuration tsconfig.json file in your working directory:

npx tsc --init

Installing BcryptJS and TypeScript Dependencies

To make sure BcryptJS is compatible with TypeScript, you will need the following Dependencies:

  • BcryptJS for hashing passwords.
  • @types/bcryptjs - type definition package for BcryptJS with TypeScript.
  • typescript gets .ts transpiled to JavaScript before being executed.
  • ts-node - TypeScript execution environment for Node.js.
  • express and @types/express to build server-side code.
  • mysql2 for connecting to MySQL database.
  • pg and @types/pg if you want to use PostgreSQL instead of MySQL.

Run the following command to make sure these packages are installed and available in your project:

npm install bcryptjs @types/bcryptjs typescript ts-node mysql2 express @types/express

Creating a Basic BcryptJS TypeScript App with Node.js

Before diving in and using BcryptJS with your Node.js TypeScript apps, let’s check a simple BcryptJS usage and understand how it works to hash passwords:

In your working directory, create an index.ts file with the following code sample:

import bcrypt from "bcryptjs";

async function runBcryptExample() {
  // Example password
  const plainTextPassword = "TestPassWord";

  try {
    // Hash the password
    const hashedPassword = await bcrypt.hash(plainTextPassword, 10);
    console.log("Hashed Password:", hashedPassword);

    // Compare the hashed password with the plain text password
    const isMatch = await bcrypt.compare(plainTextPassword, hashedPassword);
    console.log("Password Match:", isMatch);
  } catch (error) {
    console.error("Error:", error);
  }
}

runBcryptExample();

In this example, you have:

  • import BcryptJS to make sure its methods are available and you can use them.
  • Create a simple runBcryptExample method.
  • Here, provides a simple password example as plaintext.
  • Using this example password, tell TypeScript to use BcryptJS to hash the plain text password. This will simulate a user registration case.
  • If you use the same password to log in, BcryptJS should check if the password matches the hashed password and return true or if not, you’ll get an error.

Now run the app using the following command:

npx ts-node index.ts

How to Use Node.js BcryptJS Module With TypeScript

Based on my BcryptJS TypeScript example, bcrypt should hash the password to $2a$10$m3.oUkoIdqJ2fcfNm1eTTehIZM7TO5uZbZav4E9Tqi0CtryWsMZXe. To simulate a login, BcryptJS will then check if the plaintext text password matches the New HASH key. And if correct, you should get a true value.

This value will change if you run the app again. This way BcryptJS ensures TypeScript doesn’t create hashed password redundancy and your passwords have optimal security futures.

Enhancing User Authentication with BcryptJS, TypeScript, and Node

To extend BcryptJS password encryption, let’s now create a real case user Authentication app that BcryptJS will use to hash plain passwords during user registration and check for password matches during login.

You will create:

  • BcryptJS and TypeScript database connection.
  • User registration Module and use BcryptJS to hash passwords before saving them to your database.
  • Use BcryptJS and compare the hashed password with the plain text password and allow the user to log in with a plaintext password while having the hashed saved password.

Setting up Database with TypeScript to Save BcryptJS hashes

Before adding your TypeScript Database connecting code. ensure you create a Database user then use the following SQL query to create a users table and its attributes:

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

Create a database.ts file with your database connection as follows:

import { Pool } from "pg";
const pool = new Pool({
  user: "postgres", //postgres-username
  host: "localhost",
  database: "user",
  password: "your-postgres-password",
  port: 5432,
});
export default pool;

If you are using MySQL, the same connection should be established as follows:

import { createPool, Pool } from "mysql2";
const pool: Pool = createPool({
  host: "localhost",
  user: "root", //your-mysql-username
  password: "your-mysql-password",
  database: "user", // The database name you just created.
  connectionLimit: 10,
});

export default pool;

Using BcryptJS to log in and Register Users

Every time you create a new user while using your TypeScript Node.js API BcryptJS should be able to read the user request and hash the password before it is saved.

Now create a authController.ts file as follows:

  • Add imports for Express, bcrypt, and database connecting:
import { Request, Response } from "express";
import bcrypt from "bcryptjs";
import pool from "./database";

Create a user registration method as follows:

//Register a new user
export const registerUser = async (req: Request, res: Response) => {
  const { username, password } = req.body;

  // Check if both username and password are provided
  if (!username || !password) {
    return res
      .status(400)
      .json({ message: "Username and password are required" });
  }

  try {
    // Check if the username already exists in the database
    const existingUser = await pool.query(
      "SELECT * FROM users WHERE username = $1",
      [username]
    );

    // If the username exists, return error
    if (existingUser.rows.length > 0) {
      return res.status(400).json({ message: "Username already exists" });
    }

    // Hash the provided password before storing it in the database
    const passwordHash = await bcrypt.hash(password, 10);

    // Insert the new user into the database
    await pool.query("INSERT INTO users (username, password) VALUES ($1, $2)", [
      username,
      passwordHash,
    ]);

    res.status(201).json({ message: "User registered successfully" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
};

Here, the user will provide the password with a Post Request. If the user doesn’t exist in your database, bcrypt will hash the plain password with bcrypt.hash(password, 10). It then executes an INSERT query to save the results of HASH to your database and return a successful message.

  • Create a method to allow the user to log in using plaintext but ensuring it matches username and Hashed password:
// handle user login
export const loginUser = async (req: Request, res: Response) => {
  // Destructure username and password from the request body
  const { username, password } = req.body;

  // Check if both username and password are provided
  if (!username || !password) {
    return res
      .status(400)
      .json({ message: "Username and password are required" });
  }

  try {
    // Query the database to find a user with the provided username
    const user = await pool.query("SELECT * FROM users WHERE username = $1", [
      username,
    ]);

    // If no user is found, return an authentication error
    if (user.rows.length === 0) {
      return res.status(401).json({ message: "Invalid username or password" });
    }

    // Compare the provided password with the hashed password stored in the database
    const isPasswordMatch = await bcrypt.compare(
      password,
      user.rows[0].password
    );

    // If passwords don't match, return an authentication error
    if (!isPasswordMatch) {
      return res.status(401).json({ message: "Invalid username or password" });
    }

    // If everything is correct, send a success message
    res.json({ message: "Login successful" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
};

In this example, the User must provide a username and a plain text password. BcryptJS will take over with bcrypt.compare. This way, it will go to your database and check the saved password that meets the user provided details.

To get users registered on your database, create a userController.ts file and use Express and database connection as follows:

import { Request, Response } from "express";
import pool from "./database";

export const getUserProfile = async (req: Request, res: Response) => {
  // Extract the 'username' parameter from the request parameters
  const { username } = req.params;

  try {
    // Query the database to find a user with the provided username
    const user = await pool.query("SELECT * FROM users WHERE username = $1", [
      username,
    ]);

    // If no user found, return a not found error
    if (user.rows.length === 0) {
      return res.status(404).json({ message: "User not found" });
    }

    // If user found, return user profile information
    res.json({ username, message: "User profile retrieved successfully" });
  } catch (error) {
    console.error(error);
    res.status(500).json({ message: "Internal Server Error" });
  }
};

Finally, create your endpoints in your index.ts file and expose the API on port 3000:

import express from "express";
import bodyParser from "body-parser";
// Import the registeration and login methods
import { registerUser, loginUser } from "./authController";
// Make the user method available
import { getUserProfile } from "./userController";

const app = express();
const PORT = process.env.PORT || 3000;

app.use(bodyParser.json());

// Routes
app.post("/api/register", registerUser);
// To login users
app.post("/api/login", loginUser);
// to get and fetch available registered users
app.get("/api/users/:username", getUserProfile);

//Expose your API to test it
app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

Testing BcryptJS with TypeScript and Node.js

To test how BcryptJS is working, run your app using the following command:

npx ts-node index.ts

Go to Postman and send a Post Request to http://localhost:3000/api/register with user details as follows:

How to Use Node.js BcryptJS Module With TypeScript

Once you send the request, you will get a success message. You should go further and test if this is true in your database as follows:

How to Use Node.js BcryptJS Module With TypeScript

The provided password is hashed and saved without using the plaintext. If BcryptJS is working as expected, send a request to log in to the user with the password as the username.

Make sure you are sending a Post request to http://localhost:3000/api/login:

How to Use Node.js BcryptJS Module With TypeScript

If you use a different password to log in, BcryptJS should capture that and tell you have provided a wrong password that doesn’t match the saved hash:

How to Use Node.js BcryptJS Module With TypeScript

Conclusion

This Guide explained how you use TypeScript and still be able to use BcryptJS with Node.js. Note that this is a very basic example. Try exploring further and using more advanced user authentication elements such as using passport.js and adding JWT.

How to Use Node.js BcryptJS Module With TypeScript

Written By:

Joseph Chege