DEV Community

Adrian Grahl
Adrian Grahl

Posted on

Implementación de Autenticación Segura en Node.js con JWT

Introducción

La seguridad en las aplicaciones web es un aspecto fundamental, especialmente cuando manejamos información sensible. Una forma popular y segura de implementar autenticación en Node.js es mediante el uso de JWT (JSON Web Tokens). En este artículo, te mostraré cómo crear una autenticación segura utilizando JWT en una aplicación de Node.js, simulando una base de datos con un array para almacenar los usuarios.

1. ¿Qué es JWT y cómo funciona?

JWT (JSON Web Token) es un estándar que define una forma compacta y segura de transmitir información entre las partes como un objeto JSON. El token está compuesto por tres partes:

  • Header (Encabezado): Indica el tipo de token y el algoritmo de cifrado utilizado.
  • Payload (Carga útil): Contiene las declaraciones o claims, como el ID del usuario.
  • Signature (Firma): Se usa para verificar que el token no ha sido alterado.

JWT es útil para transmitir información que puede verificarse y confiarse.

2. Configuración del Proyecto en Node.js

Primero, vamos a configurar un proyecto básico de Node.js con Express y las bibliotecas necesarias.

Paso 1: Crear un nuevo proyecto e instalar dependencias

mkdir secure-auth-nodejs
cd secure-auth-nodejs
npm init -y
npm install express jsonwebtoken bcryptjs dotenv

  • Express: Para crear el servidor web.
  • jsonwebtoken: Para manejar JWT.
  • bcryptjs: Para encriptar las contraseñas.
  • dotenv: Para manejar las variables de entorno.

3. Configuración del servidor Express

Crea el archivo app.js para inicializar el servidor Express y configurar algunas rutas básicas:

const express = require('express');
const app = express();
const dotenv = require('dotenv');
dotenv.config();

app.use(express.json()); // Permite manejar JSON en las solicitudes

app.get('/', (req, res) => {
  res.send('API de autenticación segura');
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Servidor corriendo en el puerto ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode
  1. Simulación de Base de Datos: Array de Usuarios Para simplificar el ejemplo, utilizaremos un array para simular una base de datos de usuarios. Este array almacenará los usuarios registrados en memoria mientras la aplicación esté corriendo.
const users = []; // Simula una base de datos en memoria
Enter fullscreen mode Exit fullscreen mode
  1. Registro de Usuario con Contraseña Encriptada Cuando un usuario se registra, debemos encriptar su contraseña antes de guardarla. Utilizaremos bcryptjs para este propósito.
const bcrypt = require('bcryptjs');

// Ruta para registrar un nuevo usuario
app.post('/register', async (req, res) => {
  const { username, password } = req.body;

  // Verificar si el usuario ya existe
  const userExists = users.find(user => user.username === username);
  if (userExists) return res.status(400).send('El usuario ya existe');

  // Encriptar la contraseña
  const hashedPassword = await bcrypt.hash(password, 10);

  // Guardar usuario en la base de datos simulada
  const newUser = { username, password: hashedPassword };
  users.push(newUser);

  res.status(201).send('Usuario registrado exitosamente');
});
Enter fullscreen mode Exit fullscreen mode
  1. Login y Generación de JWT Al iniciar sesión, verificamos que el usuario exista y que la contraseña coincida. Si todo es correcto, generamos un JWT que el cliente utilizará para autenticar las solicitudes futuras.
const jwt = require('jsonwebtoken');

// Ruta para iniciar sesión
app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  // Buscar al usuario
  const user = users.find(u => u.username === username);
  if (!user) return res.status(400).send('Usuario no encontrado');

  // Verificar la contraseña
  const validPassword = await bcrypt.compare(password, user.password);
  if (!validPassword) return res.status(400).send('Contraseña incorrecta');

  // Generar un token JWT
  const token = jwt.sign({ username: user.username }, process.env.TOKEN_SECRET, { expiresIn: '1h' });
  res.header('auth-token', token).send(token);
});
Enter fullscreen mode Exit fullscreen mode
  1. Proteger Rutas con JWT Para proteger ciertas rutas de acceso, utilizaremos un middleware que verifique si el usuario tiene un token válido antes de permitir el acceso.
// Middleware para verificar el token JWT
function verifyToken(req, res, next) {
  const token = req.header('auth-token');
  if (!token) return res.status(401).send('Acceso denegado');

  try {
    const verified = jwt.verify(token, process.env.TOKEN_SECRET);
    req.user = verified;
    next(); // Continuar con la solicitud
  } catch (err) {
    res.status(400).send('Token inválido');
  }
}

// Ruta protegida (solo accesible con token)
app.get('/protected', verifyToken, (req, res) => {
  res.send('Accediste a una ruta protegida');
});
Enter fullscreen mode Exit fullscreen mode

8. Buenas Prácticas para la Autenticación Segura
Usar HTTPS: Siempre utiliza HTTPS para proteger la comunicación entre el cliente y el servidor.

Expiración del token: Establecer una duración limitada para los tokens (ejemplo: 1 hora) es una buena práctica para minimizar riesgos.

Almacenamiento seguro: Almacena el JWT en una cookie con el flag httpOnly para mayor seguridad.

Rotación de tokens: Implementar "refresh tokens" para manejar sesiones prolongadas de forma segura.

Conclusión

Implementar autenticación con JWT en Node.js es un proceso relativamente sencillo y eficaz para proteger las rutas y verificar la identidad del usuario. En este ejemplo, utilizamos un array para simular una base de datos, pero el mismo concepto puede aplicarse en producción utilizando una base de datos real. Con esta base, puedes expandir el sistema añadiendo características avanzadas como manejo de roles, permisos y renovaciones de tokens.

Top comments (0)