Sling Academy
Home/Node.js/How to Hash Passwords in NestJS

How to Hash Passwords in NestJS

Last updated: January 01, 2024

Introduction

When building web applications, securing user credentials is vital. In this tutorial, you will learn how to implement secure password hashing in a NestJS application using modern techniques and libraries.

Getting Started

To begin with, ensure you have a NestJS project setup. If not, create one using the following command:

nest new your-project-name

Once your project is ready, navigate to the project directory:

cd your-project-name

Installing Necessary Libraries

You will need to install bcrypt or Argon2, libraries that help in hashing passwords. Argon2 is considered very secure but can be more complex to install due to additional system dependencies, while bcrypt is widely used and easier to install:

For bcrypt:

npm install bcrypt

For Argon2:

npm install argon2

Basic Password Hashing with Bcrypt

The bcrypt algorithm is a widely used method for password hashing. Here’s how to use it in NestJS.

import * as bcrypt from 'bcrypt';

async function hashPassword(password: string): Promise {
    const salt = await bcrypt.genSalt();
    return await bcrypt.hash(password, salt);
}

Call this function whenever you need to hash a password, for instance, in the user registration process.

Using Bcrypt in NestJS Services

Integrate bcrypt into a NestJS service as follows:

import { Injectable } from '@nestjs/common';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
    async hashPassword(password: string): Promise {
        const salt = await bcrypt.genSalt();
        return await bcrypt.hash(password, salt);
    }
}

You can now inject this service into controllers where user registration occurs.

Advanced Password Hashing with Argon2

Argon2 is the winner of the Password Hashing Competition and is recommended for new applications. Here is how you can use it:

import * as argon2 from 'argon2';

async function hashPassword(password: string): Promise {
    return await argon2.hash(password);
}

Using Argon2 in NestJS with Dependency Injection

To properly utilize Argon2 in your NestJS app, create a service that uses dependency injection.

import { Injectable } from '@nestjs/common';
import * as argon2 from 'argon2';

@Injectable()
export class AuthService {
    async hashPassword(password: string): Promise {
        return argon2.hash(password);
    }
}

Just like with bcrypt, you will inject this AuthService into your registration controller.

Validating Passwords

Here’s how to verify that a user-entered password matches the hashed version stored in your database.

Bcrypt

async function validatePassword(userPassword: string, storedHashPassword: string): Promise {
    return bcrypt.compare(userPassword, storedHashPassword);
}

Argon2

async function validatePassword(userPassword: string, storedHashedPassword: string): Promise {
    return argon2.verify(storedHashedPassword, userPassword);
}

These functions can be included in your AuthService and used during login flow.

Handling Hashing Securely

To enhance the security aspect of hashing, consider the following best practices:

  • Never hash passwords synchronously.
  • Use a salt to make each hash unique.
  • Consider using a pepper (an additional secret added to the hash process).
  • Store hashes securely in your database.

Integrating Password Hashing in User Workflow

Let’s integrate password hashing in user sign-up and login processes in your NestJS application.

Registration Process

Demonstrate how to create a user signup method that hashes the password:

@PostMapping('/signup')
public async signup(@Body() body: { password: string }) {
    const hashedPassword = await this.authService.hashPassword(body.password);
    // Persisting the hashed password to the database goes here.
}

Login Process

Show an example method of a user login process that validates the password:

@PostMapping('/login')
public async login(@Body() body: { username: string, password: string }) {
    // Fetching the user and hashed password from the database goes here.
    const isPasswordValid = await this.authService.validatePassword(body.password, user.hashedPassword);
    if (!isPasswordValid) {
        throw new UnauthorizedException('Invalid credentials');
    }
    // Proceed with login process (e.g., token generation)
}

Conclusion

Effective password hashing is critical for the security of user data. By following the steps outlined in this guide and by adhering to best practices, you’ll enhance your NestJS application’s security, prevent common vulnerabilities and protect your users. Always stay updated with the latest cryptographic practices and NestJS updates.

Next Article: How to Implement Rate Limiting in NestJS

Previous Article: How to Push Server-Sent Events (SSE) in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates