DEV Community

Danny Pule
Danny Pule

Posted on • Edited on

Exclude a route from Nest.js AuthGaurd (make any route publicly available)

Create a custom class called AuthGuard that extends from the AuthGaurd class exported by @nestjs/passport. Notice the inclusion of isPublic which allows you to add a decorator to routes that you want to be publicly accessible.

 

// auth.gaurd.ts

import { ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard as PassportAuthGaurd } from '@nestjs/passport';

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

  canActivate(context: ExecutionContext) {
    const isPublic = this.reflector.get<boolean>(
      'isPublic',
      context.getHandler()
    );

    if (isPublic) {
      return true;
    }

    return super.canActivate(context);
  }
}
Enter fullscreen mode Exit fullscreen mode

 

Use this gaurd as a global gaurd in main.ts or wherever you bootstrap your application. This will lockdown all routes and make them accessible by authenticated users only.

 

// main.ts

const reflector = app.get(Reflector);
app.useGlobalGuards(new AuthGuard(reflector));
Enter fullscreen mode Exit fullscreen mode

 

Create a decorator called Public which will allow you make any route public.

 

// public.decorator.ts

import { SetMetadata } from '@nestjs/common';
export const Public = () => SetMetadata('isPublic', true);
Enter fullscreen mode Exit fullscreen mode

 

Finally add the @Public() decorator to any routes that need to be publicly accessible by unauthenticated users.

 

// auth.controller.ts

@Post('/signup')
@Public()
async signUp(
  @Body(ValidationPipe) signUpDto: SignUpDto
): Promise<{ accessToken: string; user: User }> {
  // code ...
}

@Post('/signin')
@Public()
signIn(
  @Body(ValidationPipe) authCredentialsDto: AuthCredentialsDto
): Promise<{ accessToken: string; user: User }> {
   // code ...
}
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
joe_p_7e01c699c0082b0f99d profile image
Joe P

This seems to only work on the route level. Is there a way to make this work on a controller level?

This does not work:

@Public()
@Controller()
export class AppController {

  @Get('ping')
  respondToPing() {
    return 'pong';
  }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
fsassiv profile image
FLAVIO SANTOS DE ANDRADE • Edited

I think a Custom Class decorator would be the solution for this.

1. Define the Decorator
First, create a new file for your custom decorator. Let's call it custom-class.decorator.ts.

typescript
import { SetMetadata } from '@nestjs/common';

export const CustomClass = (value: string): ClassDecorator => {
  return SetMetadata('customClassKey', value);
};
Here, SetMetadata is used to attach metadata to the class.

2. Apply the Custom Decorator
Apply this decorator to any class where you want to use it.

typescript
import { CustomClass } from './custom-class.decorator';

@CustomClass('myCustomValue')
export class ExampleService {
  // Your class logic here
}
3. Access the Metadata
To access this metadata, use the Reflector service in a guard, interceptor, or another provider.

typescript
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class CustomGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const customValue = this.reflector.get<string>(
      'customClassKey',
      context.getClass(),
    );
    if (!customValue) {
      return true;
    }

    // Add your custom logic here
    console.log(`Custom value from decorator: ${customValue}`);
    return true;
  }
}
4. Register the Guard
Finally, apply the guard either globally, at the module level, or at the route level.

typescript
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { ExampleService } from './example.service';
import { CustomGuard } from './custom.guard';

@Module({
  providers: [
    ExampleService,
    {
      provide: APP_GUARD,
      useClass: CustomGuard,
    },
  ],
})
export class AppModule
Enter fullscreen mode Exit fullscreen mode