NestJS

Nest

Tutorial Nest: Estrategia de autenticación JwtStrategy

Nest JWT strategy: autenticación y seguridad. Domina la autenticación y seguridad utilizando JWT strategy en Nest con ejemplos prácticos.

Introducción

PassportStrategy proviene de Passport, una librería de seguridad y autenticación en Node y NestJS. 

Se instala de la siguiente manera:

npm install @nestjs/jwt @nestjs/passport passport passport-jwt

PassportStrategy permite definir estrategias personalizadas de autenticación, como por ejemplo gestionar tokens JWT que llegan de frontend.

Crear estrategia JWT

En este apartado se crea una estrategia para validar los tokens JWT. 

Crear archivo jwt.strategy.ts:

import { Injectable, UnauthorizedException } from "@nestjs/common";
import { PassportStrategy } from "@nestjs/passport";
import { InjectRepository } from "@nestjs/typeorm";
import { Strategy, ExtractJwt } from 'passport-jwt';
import { Repository } from "typeorm";
import { User } from "./user.model";
import { DecodedToken } from "./decoded-token.dto";

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {

    constructor(@InjectRepository(User) private userRepository: Repository<User>) {
        // Configurar la extracción del token y la clave para verificar la firma del token
        super({
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // extrae token de header Authorization
            ignoreExpiration: false,
            secretOrKey: 'admin' // Cambiar clave secreta y leerla de variable entorno process.env.SECRETO
        });
    }

    // Valida el contenido del token JWT que llega de frontend
    async validate(payload: DecodedToken) {
        // Comprobar si el usuario es correcto
        const user = await this.userRepository.findOne({
            where: {
                id: payload.sub // id del usuario que viene en el token
            }
        });

        if(!user)
            throw new UnauthorizedException('Usuario incorrecto'); // 401

        // quitar contraseña antes de devolver el usuario
        return user;
    }


}

Activar estrategia JWT

Para activar la estrategia es necesario agregarla en la configuración providers de app.module.ts:

@Module({
  imports: [
    PassportModule, // módulo de autenticación
    JwtModule.register({
      secret: 'admin',
      signOptions: {expiresIn: '7d'}
    }),
    MulterModule.register({
      storage: diskStorage({
        // carpeta destino donde guardar los archivos
        destination: './uploads',
        // Opcional: generar un nombre único para el archivo antes de guardarlo:
        // 1f82d390-d902-4aed-ad23-d543f56f2433.png
        filename: (req, file, callback) => {
          let fileName = uuidv4() + extname(file.originalname);
          callback(null, fileName);
        }
      })
    }),
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost', 
      port: 3306,
      username: 'root',
      password: 'admin',
      database: 'nest', // crear esta base de datos en MySQL primero
      entities: [Book, Author, Category, Editorial, User, Reservation, Rating],
      synchronize: true, // generar tablas en base de datos
      logging: true
    }),
    TypeOrmModule.forFeature([Book, Author, Category, Editorial, User, Reservation, Rating]) // Esto permite acceder a Repository
    
  ],
  controllers: [BookController, .....],
  // Clase personalizada para validar y verificar token JWT, viene de jwt.strategy.ts
  providers: [JwtStrategy],
})
export class AppModule {}

Aplicar estrategia JWT en controladores

Una vez activada la estrategia, es posible aplicarla sobre los métodos de los controladores.

Ejemplo sobre un controlador de libros book.controller.ts:

    @Post()
    @UseGuards(AuthGuard('jwt')) 
    create(@Request() request, @Body() book: Book) {
        console.log("Usuario identificado: ", request.user);
        // Obligatorio ser role admin para poder guardar
        if (request.user.role !== Role.ADMIN)
            throw new UnauthorizedException('Sin permisos para crear');

        return this.bookRepository.save(book);
    }
  • @UseGuards(AuthGuard('jwt')) activa la seguridad en este método haciendo que sea obligatorio acceder con un token JWT a este endpoint.
  • @Request() request la request permite obtener el usuario que fue cargado en jwt.strategy.ts.
  • request.user acceder al usuario de la request, lo que permite saber qué usuario está navegando.
  • request.user.role acceder al rol del usuario.

Verificar estrategia JWT

Desde Postman se envía un libro al método create del book.controller.ts.

Primero se escribe un token válido en la cabecera Authorization tras haber hecho login con un usuario administrador:

Segundo se envía en el Body el nuevo libro:

El resultado debería tener un status 201 Created.

En la consola del backend NestJS el resultado debería ser que se inserta un nuevo libro en base de datos, identificando al usuario en el proceso y verificando su rol:

Obtener usuario en frontend

Aplicando la estrategia JWT en un método del controlador user.controller.ts de backend es posible obtener el usuario autenticado con toda su información en el frontend:

    @Get('account')
    @UseGuards(AuthGuard('jwt'))
    public getCurrentAccountUser(@Request() request) {
        // TODO quitar la contraseña antes de devolver el usuario
        return request.user;
    }

De este modo la url http://localhost:3000/user/account retornaría el usuario actualmente autenticado. 

Importante: si intentamos acceder a este endpoint sin especificar token JWT entonces devolverá error 401 Unauthorized:

{
    "message": "Unauthorized",
    "statusCode": 401
}
Certifícate en Nest con CertiDevs PLUS

Ejercicios de esta lección Estrategia de autenticación JwtStrategy

Evalúa tus conocimientos de esta lección Estrategia de autenticación JwtStrategy con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de Nest

Accede a todas las lecciones de Nest y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Certificados de superación de Nest

Supera todos los ejercicios de programación del curso de Nest y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  • Recibir token JWT en backend
  • Verificar la firma del token JWT
  • Securizar endpoints
  • Autenticar usuarios