Skip to content

JWT Auth Guard (src/auth/jwt.guard.ts)

Overview

The JwtAuthGuard is a custom authentication guard that extends Passport's AuthGuard to protect routes in the BidScript backend. It enforces JWT authentication for all routes except those explicitly marked as public using the @Public() decorator.

Dependencies

import { Injectable, ExecutionContext } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Reflector } from '@nestjs/core';
import { IS_PUBLIC_KEY } from './decorators/public.decorator';

Implementation

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  constructor(private reflector: Reflector) {
    super();
  }

  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.getAllAndOverride<boolean>(
      IS_PUBLIC_KEY,
      [
        context.getHandler(),
        context.getClass(),
      ],
    );

    if (isPublic) {
      return true;
    }

    return super.canActivate(context);
  }
}

Key Methods

canActivate

canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean>

Determines whether the current request is allowed to proceed.

Parameters: - context: ExecutionContext - The execution context, containing request information

Returns: - boolean | Promise<boolean> | Observable<boolean>: Whether the request should be processed

How It Works

  1. The guard is invoked for every incoming request
  2. It checks if the route is marked as public using the @Public() decorator
  3. If the route is public, the guard allows the request to proceed
  4. If the route is not public, the guard delegates to the JWT authentication strategy
  5. The JWT strategy validates the token and extracts the user information
  6. If valid, the user is attached to the request and the request proceeds
  7. If invalid, an UnauthorizedException is thrown

Public Route Exemption

The guard uses NestJS's Reflector to check for the presence of the IS_PUBLIC_KEY metadata, which is set by the @Public() decorator:

// public.decorator.ts
export const IS_PUBLIC_KEY = 'isPublic';
export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);

This allows routes to be marked as public, bypassing JWT authentication:

@Public()
@Get('public-endpoint')
publicEndpoint() {
  return { message: 'This endpoint is public' };
}

Global Application

The guard is applied globally to all routes in the application through the APP_GUARD provider in the AuthModule:

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: JwtAuthGuard,
    },
    // ...other providers
  ],
})
export class AuthModule {}

This ensures that all routes are protected by default, requiring explicit marking for public access.

Integration with Other Guards

The JwtAuthGuard can be combined with other guards like RolesGuard for role-based access control:

@UseGuards(RolesGuard)
@Roles('admin')
@Get('admin-only')
adminEndpoint() {
  return { message: 'Admin only endpoint' };
}

In this case, the JwtAuthGuard runs first (globally), then the RolesGuard.

Error Handling

When authentication fails, the guard throws an UnauthorizedException (HTTP 401) with an appropriate message:

  • Missing token: "Unauthorized"
  • Invalid token: "Invalid token"
  • Expired token: "Token expired"

These exceptions are caught by NestJS's exception filters and formatted as JSON responses.

Security Considerations

  • All routes are protected by default
  • Public routes must be explicitly marked
  • Authentication errors return standardized responses
  • The guard integrates with the JWT strategy for token validation