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.
Overview
The flow includes:
- 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. - 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 usingbcrypt.
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 tokensAPI_URL– used to generate the reset linkSMTP_HOST,SMTP_PORT,SMTP_USER,SMTP_PASS,SMTP_SECURE– used bynodemailerto 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.

Dodaj komentarz