> > > > > > > >
GRUPO EBIM 23 Dic 24

Guía para Implementar JWT en Node.js con NestJS

Compartir
  • Copiado en el portapapeles

¿Qué es un JSON Web Token?

El JSON Web Token (JWT) es un estándar abierto (RFC 7519) que define una forma compacta y autónoma de transmitir información de manera segura entre partes como un objeto JSON. Esta información se puede verificar y confiar en ella porque está firmada digitalmente. Los JWT pueden ser firmados usando un secreto (con el algoritmo HMAC) o un par de claves pública/privada utilizando RSA o ECDSA.

¿Cuándo deberías usar JSON Web Tokens?

  • Autorización: Este es el escenario más común para usar JWT. Una vez que el usuario ha iniciado sesión, cada solicitud subsiguiente incluirá el JWT, lo que permite al usuario acceder a rutas, servicios y recursos permitidos por ese token. El inicio de sesión único (Single Sign-On) utiliza ampliamente JWT debido a su pequeño tamaño y su capacidad para usarse fácilmente entre diferentes dominios.
  • Intercambio de información: Los JSON Web Tokens son una buena manera de transmitir información de manera segura entre partes. Dado que los JWT pueden estar firmados, por ejemplo, utilizando pares de claves pública/privada, puedes estar seguro de que los remitentes son quienes dicen ser. Además, como la firma se calcula utilizando el encabezado y el cuerpo, también puedes verificar que el contenido no haya sido alterado.

Configurando el Proyecto

npm i -g @nestjs/cli
nest new jwt-auth-demo
cd jwt-auth-demo

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

Definir el modelo del usuario:

// src/auth/user.model.ts
export class User {
id: number;
username: string;
password: string; // Store hashed passwords
}

Crear un servicio de usuario simple:

// src/auth/auth.service.ts
import { Injectable } from ‘@nestjs/common’;
import { User } from ‘./user.model’;
import * as bcrypt from ‘bcrypt’;

@Injectable()
export class AuthService {
private users: User[] = [];

async register(username: string, password: string): Promise<User> {
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = { id: Date.now(), username, password:

hashedPassword };
this.users.push(newUser);
return newUser;
}

async validateUser(username: string, password: string): Promise<any> {
const user = this.users.find(user => user.username === username);
if (user && await bcrypt.compare(password, user.password)) {
return user;
}
return null;
}
}

Estrategia JWT

Decide el tipo de autenticación que deseas implementar. Las opciones comunes incluyen autenticación por nombre de usuario/contraseña, inicio de sesión con redes sociales (por ejemplo, utilizando OAuth) o autenticación basada en tokens (por ejemplo, JWT).

Configurar JWT:

// src/auth/auth.module.ts
import { Module } from ‘@nestjs/common’;
import { AuthService } from ‘./auth.service’;

import { JwtModule } from ‘@nestjs/jwt’;
import { PassportModule } from ‘@nestjs/passport’;
import { JwtStrategy } from ‘./jwt.strategy’;

@Module({
imports: [
PassportModule,
JwtModule.register({
secret: ‘secretKey’, // Use environment variable for production
signOptions: { expiresIn: ’60s’ },
}),
],
providers: [AuthService, JwtStrategy],
exports: [AuthService],
})
export class AuthModule {}

Implementar la estrategia JWT:

// src/auth/jwt.strategy.ts
import { Injectable } from ‘@nestjs/common’;
import { PassportStrategy } from ‘@nestjs/passport’;
import { ExtractJwt, Strategy } from ‘passport-jwt’;
import { AuthService } from ‘./auth.service’;

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: ‘secretKey’,
});
}

async validate(payload: any) {
return this.authService.validateUser(payload.username, payload.sub);
}
}

Creación de EndPoint de autenticación:

// src/auth/auth.controller.ts
import { Controller, Post, Body, UseGuards } from ‘@nestjs/common’;
import { AuthService } from ‘./auth.service’;
import { JwtService } from ‘@nestjs/jwt’;
import { LocalAuthGuard } from ‘./local-auth.guard’;

@Controller(‘auth’)
export class AuthController {
constructor(
private readonly authService: AuthService,
private jwtService: JwtService,
) {}

    @Post(‘register’)
async register(@Body() body: { username: string; password: string }) {
return this.authService.register(body.username, body.password);
}

@UseGuards(LocalAuthGuard)
   @Post(‘login’)
async login(@Body() body: { username: string; password: string }) {
const user = await this.authService.validateUser(body.username, body.password);
const payload = { username: user.username, sub: user.id };
return {
access_token: this.jwtService.sign(payload),
};
}
}

Implementar  LocalAuthGuard

// src/auth/local-auth.guard.ts
import { Injectable } from ‘@nestjs/common’;
import { AuthGuard } from ‘@nestjs/passport’;

@Injectable()
export class LocalAuthGuard extends AuthGuard(‘local’) {}

Rutas protegidas:

Usa el decorador @UseGuards para proteger rutas específicas:

import { Controller, Get, UseGuards } from ‘@nestjs/common’;
import { JwtAuthGuard } from ‘./jwt-auth.guard’;

@Controller(‘protected’)
export class ProtectedController {
@UseGuards(JwtAuthGuard)
@Get()
getProtectedData() {
return { message: ‘This is protected data’ };
}
}

Conclusión:

Este artículo cubrió la implementación de la autenticación JWT en una aplicación de Node.js utilizando NestJS. Se destacaron los beneficios clave de JWT para la autenticación de usuarios sin estado y escalable, junto con la configuración de un módulo de autenticación, la implementación de una estrategia JWT y la creación de puntos finales seguros para el registro y el inicio de sesión de usuarios. Para mejorar aún más la seguridad de la aplicación, es recomendable explorar las mejores prácticas relacionadas con la expiración de tokens y los tokens de actualización.

 


 

En GRUPO EBIM desarrollamos soluciones TI a la medida de las necesidades de tu empresa. Somos expertos en consultoría SAP, Outsourcing de personal TI, y contamos con un equipo de profesionales dispuestos a brindar soluciones digitales escalables para tu negocio. ¡Llena nuestro formulario de contacto y obtén más información sobre los servicios que ofrecemos!
ES