@nestbolt/authentication
Features
Detailed explanation of each Feature enum value in @nestbolt/authentication, including what routes, services, and action providers each feature enables.
The Feature enum controls which parts of the authentication system are active. Pass an array of Feature values to the features option when configuring the module. Only the routes and services for enabled features are registered (with forRoot()) or accessible (with forRootAsync()).
import { Feature } from "@nestbolt/authentication";Feature.REGISTRATION
Value: "registration"
Enables user registration via the POST /register endpoint.
Routes Enabled
| Method | Route | Description |
|---|---|---|
POST | /register | Create a new user account |
Services Registered
RegistrationService-- orchestrates user creation and token generation.
Required Action Provider
This feature requires you to register a CreatesNewUsers implementation using the CREATES_NEW_USERS injection token. This action is responsible for validating the registration data, hashing the password, and persisting the new user.
import { Injectable, ConflictException } from "@nestjs/common";
import * as bcrypt from "bcrypt";
import { CreatesNewUsers, AuthUser } from "@nestbolt/authentication";
@Injectable()
export class CreateNewUser implements CreatesNewUsers {
async create(data: Record<string, any>): Promise<AuthUser> {
// Validate uniqueness, hash password, create user
const hashedPassword = await bcrypt.hash(data.password, 12);
// ... persist to your database and return the created user
}
}Register it in your module:
import { CREATES_NEW_USERS } from "@nestbolt/authentication";
@Module({
providers: [
{ provide: CREATES_NEW_USERS, useClass: CreateNewUser },
],
})
export class AppModule {}If this provider is missing at runtime, calling POST /register throws:
Error: Missing provider: CREATES_NEW_USERS. Register an implementation of CreatesNewUsers.Registration Flow
- Client sends
POST /registerwithname,email,password, andpasswordConfirmation. - The
RegisterDtovalidates the request body usingclass-validator. - The
RegistrationServicecalls yourCreatesNewUsers.create()implementation. - An
auth.registeredevent is emitted (if@nestjs/event-emitteris installed). - Access and refresh tokens are generated and returned to the client.
Feature.RESET_PASSWORDS
Value: "reset-passwords"
Enables the password reset flow with two endpoints: one to request a reset link, and one to reset the password using a token.
Routes Enabled
| Method | Route | Description |
|---|---|---|
POST | /forgot-password | Request a password reset token |
POST | /reset-password | Reset the password using a token |
Services Registered
PasswordResetService-- generates tokens, validates them, and orchestrates the password reset.
Required Providers
This feature requires two additional providers:
1. PasswordResetRepository
A storage adapter for password reset tokens. Configure it via the passwordResetRepository option:
AuthenticationModule.forRoot({
passwordResetRepository: TypeOrmPasswordResetRepository,
// ...
})The interface:
interface PasswordResetRepository {
createToken(email: string, hashedToken: string): Promise<void>;
findByEmail(email: string): Promise<{ token: string; createdAt: Date } | null>;
deleteByEmail(email: string): Promise<void>;
}2. ResetsUserPasswords
An action that performs the actual password update. Register it using the RESETS_USER_PASSWORDS token:
import { Injectable } from "@nestjs/common";
import * as bcrypt from "bcrypt";
import { ResetsUserPasswords, AuthUser, USER_REPOSITORY, UserRepository } from "@nestbolt/authentication";
import { Inject } from "@nestjs/common";
@Injectable()
export class ResetUserPassword implements ResetsUserPasswords {
constructor(
@Inject(USER_REPOSITORY) private userRepository: UserRepository,
) {}
async reset(user: AuthUser, password: string): Promise<void> {
const hashedPassword = await bcrypt.hash(password, 12);
await this.userRepository.save({
id: user.id,
password: hashedPassword,
});
}
}import { RESETS_USER_PASSWORDS } from "@nestbolt/authentication";
@Module({
providers: [
{ provide: RESETS_USER_PASSWORDS, useClass: ResetUserPassword },
],
})
export class AppModule {}Password Reset Flow
- Client sends
POST /forgot-passwordwith{ email }. - The service looks up the user by email. If found, it generates a random token, hashes it with bcrypt, and stores it via the
PasswordResetRepository. - The raw (unhashed) token is returned in the response. You are responsible for sending it to the user (e.g., via email).
- Client sends
POST /reset-passwordwith{ email, token, password, passwordConfirmation }. - The service looks up the stored token, verifies it has not expired (tokens expire after 60 minutes), and compares it with bcrypt.
- Your
ResetsUserPasswords.reset()implementation is called to update the password. - The stored token is deleted.
- An
auth.password-resetevent is emitted.
Feature.EMAIL_VERIFICATION
Value: "email-verification"
Enables email verification with HMAC-signed verification URLs.
Routes Enabled
| Method | Route | Description |
|---|---|---|
GET | /email/verify/:id/:hash | Verify an email address |
POST | /email/verification-notification | Resend the verification notification |
Both routes require JWT authentication.
Services Registered
EmailVerificationService-- generates signed verification URLs and verifies them.
How Verification URLs Work
The service generates verification data containing:
id-- the user's IDhash-- an HMAC-SHA256 hash of the user's email addresssignature-- an HMAC-SHA256 signature of theid:hash:expirespayloadexpires-- a Unix timestamp (1 hour from generation)
You construct the verification URL on your side and send it to the user. When the user visits the URL, your frontend extracts the parameters and calls GET /email/verify/:id/:hash?signature=...&expires=....
// Request verification data
const response = await fetch("/email/verification-notification", {
method: "POST",
headers: { Authorization: `Bearer ${accessToken}` },
});
const { id, hash, signature, expires } = await response.json();
// Construct your verification URL
const verifyUrl = `https://myapp.com/verify-email?id=${id}&hash=${hash}&signature=${signature}&expires=${expires}`;Verification Flow
- Authenticated user calls
POST /email/verification-notification. - If the user's email is already verified, a message is returned immediately.
- Otherwise, the service generates the verification data (id, hash, signature, expires) and returns it.
- You send the verification link to the user via your email service.
- User clicks the link. Your frontend calls
GET /email/verify/:id/:hash?signature=...&expires=.... - The service verifies that the link has not expired, the hash matches the user's email, and the signature is valid.
- The user's
emailVerifiedAtfield is set to the current timestamp. - An
auth.email-verifiedevent is emitted.
Feature.UPDATE_PROFILE_INFORMATION
Value: "update-profile-information"
Enables profile updates (name, email) for authenticated users.
Routes Enabled
| Method | Route | Description |
|---|---|---|
PUT | /user/profile-information | Update the user's profile |
This route requires JWT authentication.
Services Registered
ProfileService-- delegates to yourUpdatesUserProfileaction.
Required Action Provider
Register an UpdatesUserProfile implementation using the UPDATES_USER_PROFILE token:
import { Injectable, Inject } from "@nestjs/common";
import { UpdatesUserProfile, AuthUser, USER_REPOSITORY, UserRepository } from "@nestbolt/authentication";
@Injectable()
export class UpdateUserProfile implements UpdatesUserProfile {
constructor(
@Inject(USER_REPOSITORY) private userRepository: UserRepository,
) {}
async update(user: AuthUser, data: Record<string, any>): Promise<void> {
await this.userRepository.save({
id: user.id,
name: data.name ?? user.name,
email: data.email ?? user.email,
// If email changed, you may want to reset emailVerifiedAt
...(data.email && data.email !== user.email
? { emailVerifiedAt: null }
: {}),
});
}
}import { UPDATES_USER_PROFILE } from "@nestbolt/authentication";
@Module({
providers: [
{ provide: UPDATES_USER_PROFILE, useClass: UpdateUserProfile },
],
})
export class AppModule {}Feature.UPDATE_PASSWORDS
Value: "update-passwords"
Enables password changes for authenticated users. This is for users who know their current password and want to change it -- distinct from the password reset flow (which is for users who forgot their password).
Routes Enabled
| Method | Route | Description |
|---|---|---|
PUT | /user/password | Update the user's password |
This route requires JWT authentication.
Services Registered
PasswordService-- delegates to yourUpdatesUserPasswordsaction and emits theauth.password-updatedevent.
Required Action Provider
Register an UpdatesUserPasswords implementation using the UPDATES_USER_PASSWORDS token:
import { Injectable, Inject, UnprocessableEntityException } from "@nestjs/common";
import * as bcrypt from "bcrypt";
import {
UpdatesUserPasswords,
AuthUser,
USER_REPOSITORY,
UserRepository,
} from "@nestbolt/authentication";
@Injectable()
export class UpdateUserPassword implements UpdatesUserPasswords {
constructor(
@Inject(USER_REPOSITORY) private userRepository: UserRepository,
) {}
async update(user: AuthUser, data: Record<string, any>): Promise<void> {
const currentPasswordValid = await bcrypt.compare(
data.currentPassword,
user.password,
);
if (!currentPasswordValid) {
throw new UnprocessableEntityException(
"The provided password does not match your current password.",
);
}
if (data.password !== data.passwordConfirmation) {
throw new UnprocessableEntityException(
"The password confirmation does not match.",
);
}
const hashedPassword = await bcrypt.hash(data.password, 12);
await this.userRepository.save({
id: user.id,
password: hashedPassword,
});
}
}import { UPDATES_USER_PASSWORDS } from "@nestbolt/authentication";
@Module({
providers: [
{ provide: UPDATES_USER_PASSWORDS, useClass: UpdateUserPassword },
],
})
export class AppModule {}Feature.TWO_FACTOR_AUTHENTICATION
Value: "two-factor-authentication"
Enables a complete TOTP-based two-factor authentication system with QR codes, secret key management, confirmation flow, recovery codes, and challenge-based login.
Routes Enabled
| Method | Route | Description |
|---|---|---|
POST | /user/two-factor-authentication | Enable 2FA for the user |
DELETE | /user/two-factor-authentication | Disable 2FA for the user |
POST | /user/confirmed-two-factor-authentication | Confirm 2FA setup with a TOTP code |
GET | /user/two-factor-qr-code | Get a QR code SVG and otpauth URL |
GET | /user/two-factor-secret-key | Get the raw TOTP secret key |
GET | /user/two-factor-recovery-codes | Get current recovery codes |
POST | /user/two-factor-recovery-codes | Regenerate recovery codes |
POST | /two-factor-challenge | Complete 2FA login with code or recovery code |
All /user/* routes require JWT authentication. The /two-factor-challenge route is public (it uses the challenge token from the login response).
Services Registered
TwoFactorService-- manages 2FA enable/disable, code validation, QR codes, and recovery codes.TwoFactorProviderService-- wraps theotplibauthenticator for TOTP operations andqrcodefor SVG generation.
No Additional Providers Required
Unlike other features, two-factor authentication does not require any custom action providers. Everything is handled internally by the package.
Two-Factor Login Flow
- User calls
POST /loginwith their credentials. - If the user has 2FA enabled, the login endpoint returns
{ twoFactor: true, challengeToken: "..." }instead of access/refresh tokens. - The user enters their TOTP code from their authenticator app (or a recovery code).
- Client sends
POST /two-factor-challengewith{ challengeToken, code }or{ challengeToken, recoveryCode }. - If the code is valid, access and refresh tokens are returned.
- If the code is invalid, a
422 Unprocessable Entityresponse is returned and the attempt is counted against the rate limit.
Recovery Codes
When 2FA is enabled, 8 recovery codes are generated and stored (encrypted) in the database. Each recovery code can be used once -- after use, it is replaced with a new code. Users can regenerate all recovery codes at any time.
Configuration
See twoFactorOptions in the Configuration page for options like confirm, confirmPassword, window, and secretLength.
Always-Available Features
The following functionality is always available regardless of which features are enabled:
Core Authentication
| Method | Route | Description |
|---|---|---|
POST | /login | Authenticate with username and password |
POST | /refresh | Refresh access token using a refresh token |
POST | /logout | Log out (requires JWT) |
Password Confirmation
| Method | Route | Description |
|---|---|---|
POST | /user/confirm-password | Confirm the user's password |
GET | /user/confirmed-password-status | Check if password was recently confirmed |
These routes are always registered because the AuthController and ConfirmPasswordController are core components, not feature-gated.
Next Steps
- API Routes -- complete request/response reference for all endpoints.
- Decorators and Guards -- use the package's decorators and guards in your own controllers.
Configuration
Complete reference for all @nestbolt/authentication module configuration options, including JWT settings, rate limiting, two-factor authentication, and async configuration.
API Routes
Complete reference for all 19 authentication endpoints provided by @nestbolt/authentication, including request bodies, response formats, and error codes.