DEV Community

Bryan Granado
Bryan Granado

Posted on

How to implement authentication with nestjs using guards in 3 easy steps

Currently many companies has change the perspective to do a application, many frameworks and libraries up at date, was changed the developement form and them implementation themselves has doing that exist solutions to problem reallity complex. Today, we tell a litte bit about nestjs, that's a framework progressive for backend with javascript, through which can create scalables applications of a clean mode and ordered.

So, but, ¿Wich topics we'll talk? , Let' s talking about Guards in Nestjs, a tools multidiciplinary, that allow implement anything logic before of a request arrive ours controllers.

The official concepts is a class annotated with the @Injectable() decorator, which implements the CanActivate interfaceGuard have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (like permissions, roles, ACLs, etc.) present at run-time. This is often referred to as authorization. Authorization (and its cousin, authentication, with which it usually collaborates) has typically been handled by middleware in traditional Express applications. Middleware is a fine choice for authentication, since things like token validation and attaching properties to the request object are not strongly connected with a particular route context (and its metadata).

In this blog do not talk about all that can do with this functionality, specifycly look how implements a guard for authentication without install nothing and easy form. Let's go

Zero step:

We must have a create a Nestjs project at our computers, for to do this, review , important too, you has must create a module, with any functionality, else you must create a module with:

npm g module Foo

Enter fullscreen mode Exit fullscreen mode

And complete step with next and done !


First step:

The first that we'll must do is create a guard, for this we use the command:

nest generate gu FooGuard

Enter fullscreen mode Exit fullscreen mode

This command, will create something like this:

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class FooGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    return true;
  }
}
Enter fullscreen mode Exit fullscreen mode

We remember, that this Guard implements a interface CanActivate, that is who management all logic of our guard.

Ok, after let's create own decorator, is very important, because this will call by dependency injection, into our guard

import { SetMetadata } from '@nestjs/common';
import { FooEnum } from './FooEnum.enum';

export const FooRolesDecorator = (...fooRolesDecorator: FooRolesDecorator[]) =>
  SetMetadata('fooRolesDecorator', FooEnum);

Enter fullscreen mode Exit fullscreen mode

**Important: **Is'nt necesary create a Enum, but is very recommended by nestjs, for best practices, more info: https://docs.nestjs.com/openapi/types-and-parameters#enums


Second step:

Once created a guard file and his decorator, let's to implementation, for this is very important that you have knowledge about drive the dependency injection. For drive ecosistems with dependy injection, nestjs, provide a interface al ready to use, ExecutionContext, that basically is do that to describing details about the current request pipeline and return two methods, getClass(), that returns the type of the controller class which the current handler belongs to, and getHandler() that returns a reference to the handler (method) that will be invoked next in the
request pipeline. For morte info: https://docs.nestjs.com/guards#execution-context

So, after understand this concept, use this class, is to take a parameter, that will be, our role.

@Injectable()
export class FooGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    @Inject('MY_REPO_IN_MODULE')
    private myRepoInModule: Repository<MiModel>,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const role = this.reflector.getAllAndOverride<
      FooRolesDecorator[]
    >('fooRolesDecorator ', [context.getHandler(), context.getClass()]);

    if (!role ) {
      return false;
    }

    const request = context.switchToHttp().getRequest();
    const user = request.headers['user-id'];


    if (!user) {
      throw new HttpException(
        {
          status: 403,
          error: `Do not have authorization`,
        },
        403,
      );
    }

    const roleUser = await this.myRepoInModule.findOne({
      where: {user_id: user.userId});

    if (!reqUser) {
      throw new HttpException(
        {
          status: 403,
          error: `Do not have authorization`,
        },
        403,
      );
    }
  }
    return true;
  }
}

Enter fullscreen mode Exit fullscreen mode

  • HINT: The Reflector helper is using for retrieve metadata for a specified key for a specified target. A little words, get data that set into our Decorator.

  • HINT: The method, getRequest() to allow, obtain object request, from the context.

  • HINT: The Guards take the (Repositories, entities) from modules where these was called, of automatically.


Third step:

In this last step, to implement into anything controller(preferly), into you application.

@Controller('api/foo')
@UseGuards(FooGuard)
export class RolesController {
  constructor(private readonly rolesService: RolesService) {}

  @Get()
  @FooRolesDecorator(MyEnum.Admin || 'Admin')
  create(@Body() createRoleDto: CreateRoleDto) {
    return this.rolesService.create(createRoleDto);
  }
}

Enter fullscreen mode Exit fullscreen mode

  • HINT: The @UseGuards() Decorator that binds guards to the scope of the controller or method, depending on its context. When @UseGuards is used at the controller level, the guard will be applied to every handler (method) in the controller.

  • HINT: The decorator, @FooRolesDecorator() allow through dependency injection, set to parameter, for validate his needed's authorization.

Done!!

A Guard with nest a 3 easy steps ...

Don't forget follow in my social media:

@brngranado at instagram
@brngranado at twitter
@GranadoLab at Github

See you there !

Top comments (0)