Day#12 Password Reset Flow with JWT in a NestJS Backend

Today I implemented a complete password reset mechanism in a NestJS backend API. It consists of two public endpoints and uses a stateless approach based on JWT for token management.

mariusz
mariusz
20 posts
2 followers

Overview

The flow includes:

  1. Requesting a password reset link
    POST /auth/remind-password
    Accepts an email address. If the user exists, a time-limited JWT token is generated and sent to the email address. The token contains only the user ID (sub) and expires in 15 minutes.
  2. Resetting the password
    POST /auth/reset-password
    Accepts the token and a new password. The token is verified using a separate secret (JWT_RESET_PASSWORD_SECRET), and the password is updated using bcrypt.

Both endpoints are public, meaning no authentication is required.


Implementation Details

Token generation

const token = this.jwtService.sign(
  { sub: partner.id },
  {
    expiresIn: '15m',
    secret: process.env.JWT_RESET_PASSWORD_SECRET,
  }
);

Token verification and password update

const { sub: userId } = this.jwtService.verify(token, {
  secret: process.env.JWT_RESET_PASSWORD_SECRET,
});
const partner = await this.partnerRepo.findOneBy({ id: userId });
const passwordHash = await bcrypt.hash(newPassword, 10);
partner.passwordHash = passwordHash;
await this.partnerRepo.save(partner);

Mail sending utility

We use nodemailer with SMTP credentials from environment variables. Both text and html bodies are supported, but currently, only a simple text body is generated with the reset link.

Validation

Handled by class-validator decorators in DTOs. Examples:

@IsString()
@MinLength(32)
token!: string;

@IsString()
@MinLength(8)
password!: string;

Swagger documentation

Both endpoints are described in the Swagger schema with example payloads and expected responses.


Environment Variables

The following variables must be configured:

  • JWT_RESET_PASSWORD_SECRET – used to sign/verify password reset tokens
  • API_URL – used to generate the reset link
  • SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_SECURE – used by nodemailer to send emails

Notes

The implementation is intentionally simple and avoids storing password reset tokens in the database. Since JWTs are self-contained and short-lived, there’s no need for cleanup jobs or additional tables.

Possible future improvements

  • HTML template support for emails
  • IP/device logging for reset attempts
  • Rate-limiting per IP or per email address
  • Frontend integration for the reset form

This approach keeps the logic focused and easy to test, while providing all the expected functionality for a secure password reset flow.


Opublikowano

w

,

przez

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *