Nest Authbeta

Guards

NestAuthAuthGuard and AdminSessionGuard.

NestAuthAuthGuard

The main guard. There are two ways to apply it — pick one:

Opt-in (recommended for most apps) — put @Auth() (or @UseGuards(NestAuthAuthGuard)) on the specific routes/controllers you want protected. Everything else stays open. Nothing else to configure.

@Get('profile')
@Auth()
getProfile(@CurrentUser() user) { … }

Global guard + @Public() opt-out — apply the guard app-wide and mark open routes @Public(). Good when "secure by default, list the exceptions" fits your app better.

import { APP_GUARD } from '@nestjs/core';
import { NestAuthAuthGuard } from '@ackplus/nest-auth';
 
@Module({
  providers: [
    { provide: APP_GUARD, useClass: NestAuthAuthGuard },
  ],
})
export class AppModule {}
@Public()           // opts this route out of the global guard
@Get('health')
health() { return { ok: true }; }

Both modes work out of the box. The library's own public endpoints (/auth/login, /auth/signup, /auth/refresh-token, /auth/forgot-password, /auth/reset-password, the SSO callback, client-config, …) are already marked @Public(), so a global guard never blocks login. The admin console is likewise exempt — it authenticates with its own cookie-based AdminSessionGuard, not NestAuth JWTs, so a global NestAuthAuthGuard is not applied to it.

What it does, in order, on every request:

  1. Checks for @Public() — if present, skip everything below.
  2. Calls guards.beforeAuth(request) — your hook can { reject: true, reason: '...' } to short-circuit (used for IP allowlists, device fingerprinting, etc.).
  3. Reads the Authorization header (or cookie) and decides whether it's a JWT or an API key.
  4. Validates the token / key.
  5. Resolves the active tenant.
  6. Loads userAccess for the user + tenant.
  7. Resolves roles via authorization.resolveRoles (default: read from DB).
  8. Resolves permissions via authorization.resolvePermissions (default: expand from roles).
  9. Checks any @NestAuthRoles and @NestAuthPermissions constraints.
  10. Checks MFA enforcement (skipped if @SkipMfa() is on the route).
  11. Calls guards.afterAuth(request, user) — last chance to reject.
  12. Populates the request context (decorators above will see this).

If anything fails, the guard throws — your AuthExceptionFilter (registered in main.ts) turns that into a structured response with an error code from AUTH_ERROR_CODES.

AdminSessionGuard

Protects the embedded admin console. Applied automatically to every route under adminConsole.basePath. Validates the admin session cookie and (optionally) the admin's MFA status.

You don't usually apply this guard yourself — AdminConsoleModule registers it on its own controllers. See Admin Console.

Custom guards on top

You can chain your own guards after NestAuthAuthGuard runs. By the time your guard executes, request.user, request.session, request.tenantId are all set.

@Injectable()
export class TeamMemberGuard implements CanActivate {
  canActivate(ctx: ExecutionContext): boolean {
    const req = ctx.switchToHttp().getRequest();
    return req.userAccess?.metadata?.team === req.params.teamSlug;
  }
}
 
// On a route:
@Auth()
@UseGuards(TeamMemberGuard)
@Get(':teamSlug')
list() { … }

Practical patterns

  • Optional auth@Auth(true) makes context available when present without enforcing it.
  • Test stubs — in tests, override NestAuthAuthGuard with a stub that injects whatever user you want. See Testing Your Auth.
  • IP allowlist — add the policy to guards.beforeAuth so it runs on every authenticated route. See the IP allowlist recipe.

On this page