NestboltNestbolt

@nestbolt/authentication

Decorators and Guards

Reference for all decorators and guards exported by @nestbolt/authentication, with usage examples for building custom protected controllers.

The authentication module exports several decorators and guards that you can use in your own controllers and services to build protected routes, extract the current user, enforce feature flags, and more.

Decorators

@CurrentUser()

A parameter decorator that extracts the authenticated user from the request object. This is the primary way to access the current user in your route handlers.

Import:

import { CurrentUser } from "@nestbolt/authentication";

Usage:

import { Controller, Get, UseGuards } from "@nestjs/common";
import { CurrentUser, JwtAuthGuard } from "@nestbolt/authentication";
import { AuthUser } from "@nestbolt/authentication";

@Controller("profile")
@UseGuards(JwtAuthGuard)
export class ProfileController {
  @Get()
  getProfile(@CurrentUser() user: AuthUser) {
    return {
      id: user.id,
      name: user.name,
      email: user.email,
      emailVerified: user.emailVerifiedAt !== null,
      twoFactorEnabled: user.twoFactorSecret !== null,
    };
  }
}

The decorator reads request.user, which is populated by the JWT strategy after successful token validation. If the route is not protected by JwtAuthGuard (or another authentication guard), user will be undefined.

With custom user type:

If your user entity extends AuthUser with additional fields, you can type the parameter accordingly:

import { CurrentUser } from "@nestbolt/authentication";

interface MyUser extends AuthUser {
  role: string;
  avatarUrl: string | null;
}

@Get()
getProfile(@CurrentUser() user: MyUser) {
  return {
    id: user.id,
    name: user.name,
    role: user.role,
    avatarUrl: user.avatarUrl,
  };
}

@Public()

A metadata decorator that marks a route as publicly accessible, bypassing JWT authentication. When applied to a route or controller, the JwtAuthGuard skips token validation and allows the request to proceed without authentication.

Import:

import { Public } from "@nestbolt/authentication";

Usage on a route:

import { Controller, Get, UseGuards } from "@nestjs/common";
import { Public, JwtAuthGuard } from "@nestbolt/authentication";

@Controller()
@UseGuards(JwtAuthGuard)
export class AppController {
  @Get("dashboard")
  getDashboard() {
    // This route requires authentication
    return { message: "Welcome to your dashboard." };
  }

  @Public()
  @Get("health")
  healthCheck() {
    // This route is accessible without authentication
    return { status: "ok" };
  }
}

Usage on a controller:

import { Controller, Get } from "@nestjs/common";
import { Public } from "@nestbolt/authentication";

@Controller("public")
@Public()
export class PublicController {
  @Get("status")
  getStatus() {
    return { status: "ok" };
  }

  @Get("version")
  getVersion() {
    return { version: "1.0.0" };
  }
}

How it works:

The @Public() decorator sets a metadata key (isPublic) on the route handler or controller class. The JwtAuthGuard checks for this metadata using the NestJS Reflector. If the key is present and true, the guard returns true without performing token validation.

// Exported constant for the metadata key
import { IS_PUBLIC_KEY } from "@nestbolt/authentication";
// IS_PUBLIC_KEY = "isPublic"

Using with a global guard:

If you set JwtAuthGuard as a global guard, @Public() allows you to selectively opt routes out of authentication:

import { Module } from "@nestjs/common";
import { APP_GUARD } from "@nestjs/core";
import { JwtAuthGuard } from "@nestbolt/authentication";

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: JwtAuthGuard,
    },
  ],
})
export class AppModule {}

With this setup, all routes require authentication by default. Use @Public() on specific routes or controllers to make them publicly accessible.


@RequiresFeature()

A metadata decorator that associates a route or controller with a specific Feature enum value. When used together with FeatureEnabledGuard, routes for disabled features return a 404 Not Found response.

Import:

import { RequiresFeature } from "@nestbolt/authentication";

Usage:

import { Controller, Post, Body, UseGuards } from "@nestjs/common";
import {
  RequiresFeature,
  FeatureEnabledGuard,
  Feature,
} from "@nestbolt/authentication";

@Controller("newsletter")
@RequiresFeature(Feature.REGISTRATION)
@UseGuards(FeatureEnabledGuard)
export class NewsletterController {
  @Post("subscribe")
  subscribe(@Body() body: { email: string }) {
    // This route is only accessible when Feature.REGISTRATION is enabled
    return { message: "Subscribed successfully." };
  }
}

How it works:

The decorator sets a metadata key (requiredFeature) with the Feature value. The FeatureEnabledGuard reads this metadata, checks if the feature is in the configured features array, and throws a NotFoundException if it is not.

// Exported constant for the metadata key
import { REQUIRED_FEATURE_KEY } from "@nestbolt/authentication";
// REQUIRED_FEATURE_KEY = "requiredFeature"

Guards

JwtAuthGuard

An authentication guard that validates JWT access tokens. It extends Passport's AuthGuard("jwt") and adds support for the @Public() decorator.

Import:

import { JwtAuthGuard } from "@nestbolt/authentication";

Usage:

import { Controller, Get, UseGuards } from "@nestjs/common";
import { JwtAuthGuard, CurrentUser } from "@nestbolt/authentication";

@Controller("orders")
@UseGuards(JwtAuthGuard)
export class OrdersController {
  @Get()
  getOrders(@CurrentUser() user: AuthUser) {
    // Only accessible with a valid JWT access token
    return [];
  }
}

Behavior:

  1. Extracts the JWT from the Authorization: Bearer <token> header.
  2. Verifies the token signature and expiration using the configured jwtSecret.
  3. Calls JwtStrategy.validate() to look up the user by the sub claim.
  4. Sets request.user to the resolved user object.
  5. If the route has the @Public() metadata, skips all validation and returns true.

As a global guard:

import { APP_GUARD } from "@nestjs/core";
import { JwtAuthGuard } from "@nestbolt/authentication";

@Module({
  providers: [
    { provide: APP_GUARD, useClass: JwtAuthGuard },
  ],
})
export class AppModule {}

LocalAuthGuard

An authentication guard that validates username/password credentials using the Passport local strategy. This guard is not used internally by the authentication module (the AuthController handles login directly), but it is exported for use in custom authentication flows.

Import:

import { LocalAuthGuard } from "@nestbolt/authentication";

Usage:

import { Controller, Post, UseGuards, Req } from "@nestjs/common";
import { LocalAuthGuard } from "@nestbolt/authentication";

@Controller("auth")
export class CustomAuthController {
  @Post("login")
  @UseGuards(LocalAuthGuard)
  login(@Req() req: { user: AuthUser }) {
    // req.user is populated by the local strategy after successful validation
    return { userId: req.user.id };
  }
}

Behavior:

  1. Extracts the username (from the field configured by usernameField) and password from the request body.
  2. Calls AuthService.validateCredentials() to verify the credentials.
  3. If valid, sets request.user to the authenticated user.
  4. If invalid, throws a 401 Unauthorized exception.

GuestGuard

A guard that only allows unauthenticated users. If a user is already authenticated (i.e., request.user exists), the guard throws a 403 Forbidden exception.

Import:

import { GuestGuard } from "@nestbolt/authentication";

Usage:

import { Controller, Get, UseGuards } from "@nestjs/common";
import { GuestGuard } from "@nestbolt/authentication";

@Controller("landing")
export class LandingController {
  @Get()
  @UseGuards(GuestGuard)
  getLandingPage() {
    // Only accessible to unauthenticated users
    return { message: "Welcome! Please sign in or register." };
  }
}

Error response when authenticated:

{
  "statusCode": 403,
  "message": "You are already authenticated.",
  "error": "Forbidden"
}

FeatureEnabledGuard

A guard that checks whether a specific feature is enabled in the module configuration. Used together with the @RequiresFeature() decorator.

Import:

import { FeatureEnabledGuard } from "@nestbolt/authentication";

Usage:

import { Controller, Get, UseGuards } from "@nestjs/common";
import {
  FeatureEnabledGuard,
  RequiresFeature,
  Feature,
} from "@nestbolt/authentication";

@Controller("invites")
@RequiresFeature(Feature.REGISTRATION)
@UseGuards(FeatureEnabledGuard)
export class InviteController {
  @Get()
  getInvites() {
    return [];
  }
}

Behavior:

  1. Reads the requiredFeature metadata from the route handler or controller class.
  2. If no metadata is set, the guard passes (returns true).
  3. If the metadata is set, checks if the feature is in the configured features array.
  4. If the feature is not enabled, throws a NotFoundException (404).

LoginThrottleGuard

A rate-limiting guard for login attempts. Tracks failed attempts per username+IP combination and blocks requests when the limit is exceeded.

Import:

import { LoginThrottleGuard } from "@nestbolt/authentication";

This guard is used internally on the POST /login endpoint. You generally do not need to apply it to your own routes. It is exported primarily for testing or advanced customization scenarios.

Configuration:

The guard reads its configuration from the loginRateLimit option:

loginRateLimit: { ttl: 60000, limit: 5 }
// 5 failed attempts per 60 seconds, per username+IP

Error response when rate limited:

{
  "statusCode": 429,
  "message": "Too many login attempts. Please try again in 45 seconds."
}

The auth.lockout event is emitted when the rate limit is reached.


TwoFactorThrottleGuard

A rate-limiting guard for two-factor challenge attempts. Tracks failed attempts per IP address.

Import:

import { TwoFactorThrottleGuard } from "@nestbolt/authentication";

Configuration:

twoFactorRateLimit: { ttl: 60000, limit: 5 }
// 5 failed attempts per 60 seconds, per IP

Error response when rate limited:

{
  "statusCode": 429,
  "message": "Too many two-factor attempts. Please try again in 30 seconds."
}

VerificationThrottleGuard

A rate-limiting guard for email verification notification requests. Tracks attempts per user ID+IP combination.

Import:

import { VerificationThrottleGuard } from "@nestbolt/authentication";

Configuration:

verificationRateLimit: { ttl: 60000, limit: 6 }
// 6 requests per 60 seconds, per user+IP

Error response when rate limited:

{
  "statusCode": 429,
  "message": "Too many verification attempts. Please try again in 15 seconds."
}

PasswordConfirmedGuard

A guard that requires the user to have recently confirmed their password. This is used on sensitive operations like enabling/disabling two-factor authentication.

Import:

import { PasswordConfirmedGuard } from "@nestbolt/authentication";

Usage:

import { Controller, Delete, UseGuards, Param } from "@nestjs/common";
import {
  JwtAuthGuard,
  PasswordConfirmedGuard,
  CurrentUser,
} from "@nestbolt/authentication";

@Controller("account")
@UseGuards(JwtAuthGuard)
export class AccountController {
  @Delete()
  @UseGuards(PasswordConfirmedGuard)
  deleteAccount(@CurrentUser() user: AuthUser) {
    // Only accessible if the user recently confirmed their password
    return { message: "Account deleted." };
  }
}

Behavior:

  1. If twoFactorOptions.confirmPassword is false (the default), the guard always passes.
  2. If twoFactorOptions.confirmPassword is true, the guard checks user.passwordConfirmedAt.
  3. If passwordConfirmedAt is null, throws 403 Forbidden: Password confirmation required.
  4. If passwordConfirmedAt is older than passwordTimeout seconds, throws 403 Forbidden: Password confirmation has expired.

To confirm the password, the client must first call POST /user/confirm-password.

Error responses:

{
  "statusCode": 403,
  "message": "Password confirmation required.",
  "error": "Forbidden"
}
{
  "statusCode": 403,
  "message": "Password confirmation has expired.",
  "error": "Forbidden"
}

Combining Guards

You can combine multiple guards on a single route. They execute in order, and the first guard to deny access stops the chain:

import { Controller, Post, UseGuards, Body } from "@nestjs/common";
import {
  JwtAuthGuard,
  PasswordConfirmedGuard,
  FeatureEnabledGuard,
  RequiresFeature,
  CurrentUser,
  Feature,
} from "@nestbolt/authentication";

@Controller("admin")
@UseGuards(JwtAuthGuard)
export class AdminController {
  @Post("dangerous-action")
  @RequiresFeature(Feature.UPDATE_PROFILE_INFORMATION)
  @UseGuards(FeatureEnabledGuard, PasswordConfirmedGuard)
  dangerousAction(@CurrentUser() user: AuthUser) {
    // 1. JwtAuthGuard verifies the JWT token
    // 2. FeatureEnabledGuard checks the feature is enabled
    // 3. PasswordConfirmedGuard checks recent password confirmation
    return { message: "Action performed." };
  }
}

Next Steps

  • Events -- subscribe to authentication lifecycle events.
  • API Routes -- complete endpoint reference.