La seguridad en APIs es esencial para proteger datos sensibles. JSON Web Tokens (JWT) proporciona un mecanismo robusto para autenticar y autorizar usuarios. Este artículo explica cómo implementar JWT en una API REST usando Node.js y Express.
Estructura de JWT
Un JWT consta de tres partes codificadas en Base64: encabezado, carga útil y firma. El encabezado especifica el algoritmo de firma (por ejemplo, HS256), la carga útil contiene cllaims como el ID de usuario y la expiración, y la firma verifica la integridad del token.
Instalación de Dependencias
npm install express jsonwebtoken dotenv
Configuración del Servidor Express
const express = require('express');
const jwt = require('jsonwebtoken');
require('dotenv').config();
const app = express();
app.use(express.json());
const claveSecreta = process.env.JWT_SECRET || 'mi_clave_segura_2024';
Generación de Tokens
Al autenticar un usuario, se crea un token con un tiempo de expiración limitado.
function crearToken(usuarioId, rol) {
const cargaUtil = {
sub: usuarioId,
role: rol,
iss: 'api-ejemplo',
exp: Math.floor(Date.now() / 1000) + 3600 // Expira en 1 hora
};
return jwt.sign(cargaUtil, claveSecreta, { algorithm: 'HS256' });
}
app.post('/login', (req, res) => {
const { nombreUsuario, contrasena } = req.body;
// Validación simulada (en producción, verificar contra base de datos)
if (nombreUsuario === 'admin' && contrasena === '1234') {
const tokenJWT = crearToken('101', 'administrador');
res.json({ token: tokenJWT });
} else {
res.status(401).json({ error: 'Credenciales inválidas' });
}
});
Middleware de Verificación
Se crea un middleware para proteger rutas, verificando el token en el encabezado Authoriztaion.
function verificarAutenticacion(req, res, proximo) {
const encabezadoAuth = req.headers.authorization;
if (!encabezadoAuth || !encabezadoAuth.startsWith('Bearer ')) {
return res.status(403).json({ error: 'Token no proporcionado' });
}
const tokenExtraido = encabezadoAuth.split(' ')[1];
try {
const payloadVerificado = jwt.verify(tokenExtraido, claveSecreta, { algorithms: ['HS256'] });
req.usuario = payloadVerificado;
proximo();
} catch (error) {
res.status(401).json({ error: 'Token inválido o expirado' });
}
}
app.get('/perfil', verificarAutenticacion, (req, res) => {
res.json({ mensaje: `Bienvenido, usuario ${req.usuario.sub}` });
});
Autorización Basada en Roles
Se puede extender el middleware para verificar roles específicos.
function verificarRol(rolPermitido) {
return (req, res, proximo) => {
if (req.usuario.role !== rolPermitido) {
return res.status(403).json({ error: 'Acceso denegado' });
}
proximo();
};
}
app.delete('/usuarios/:id', verificarAutenticacion, verificarRol('administrador'), (req, res) => {
res.json({ mensaje: `Usuario ${req.params.id} eliminado por ${req.usuario.sub}` });
});
Pruebas y Seguridad
Para probar, envíe una solicitud POST a /login con credenciales válidas, luego use el token obtenido en el encabezado Authorization de rutas protegidas.
// Ejemplo de solicitud con curl
// curl -X POST http://localhost:3000/login -H "Content-Type: application/json" -d '{"nombreUsuario":"admin","contrasena":"1234"}'
// curl -H "Authorization: Bearer <token>" http://localhost:3000/perfil</token>
Prácticas recomendadas: usar HTTPS, almacenar claves secretas en variables de entorno, implementar rotación de claves y limitar la duración del token.