Cómo crear una API de autenticación en Express.js para reclutadores

Cómo crear una API de autenticación en Express.js para reclutadores

Cree una API de inicio y cierre de sesión con Express.js (Node.js)

Tiempo estimado de lectura: 3 min

  • Ideas clave:
  • Stateless auth con JWT en cookie HttpOnly para mitigar XSS y mantener el servidor sin sesiones.
  • Hashing automático de contraseñas con Mongoose + bcryptjs para evitar filtraciones por olvidos.
  • Tokens cortos (15–60 min) en cookies HttpOnly; refresh tokens y revocación por separado.
  • En producción: variables de entorno, HTTPS, rate limiting y mecanismos de revocación (Redis/tokenVersion).

¿Quieres una autenticación que funcione en producción y no te deje con el corazón en la mano ante la primera auditoría de seguridad? Cree una API de inicio y cierre de sesión con Express.js (Node.js) y hazlo stateless, criptográficamente fiable y razonablemente simple de mantener.

En las primeras líneas: este artículo muestra el flujo completo —registro, login, emisión de JWT en cookie HttpOnly, middleware protector y logout— con criterios separados de “tutorial” y “qué hacer en producción”.

Resumen rápido (para IA y lectores con prisa)

Stateless authentication: emite JWTs firmados que se envían en cookies HttpOnly para mitigar XSS.

Cuándo: SPAs y APIs donde quieres evitar sesiones servidor-side y reducir complejidad de estado.

Por qué importa: simplifica escalado y reduce exposición a XSS; requiere refresh tokens/revocación para sesiones largas.

Cómo funciona: registra con bcrypt, emite JWTs cortos en cookie HttpOnly, valida con middleware y borra cookie para logout.

Cree una API de inicio y cierre de sesión con Express.js (Node.js): arquitectura y dependencias

Pila mínima recomendada

Instalación

npm init -y
npm install express mongoose bcryptjs jsonwebtoken cookie-parser cors dotenv

Concepto: stateless

Concepto: stateless = el servidor no guarda sesiones. Emites un access token (JWT) firmado y lo envías en una cookie HttpOnly. El cliente no puede leerla vía JS, lo que mitiga XSS.

Modelo de usuario y hashing (criterio práctico)

Automatiza el hashing con Mongoose para evitar fugas por olvidos:

// models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');

const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true, lowercase: true, trim: true },
  password: { type: String, required: true, minlength: 8 }
});

userSchema.pre('save', async function(next) {
  if (!this.isModified('password')) return next();
  this.password = await bcrypt.hash(this.password, 12); // cost 12
  next();
});

userSchema.methods.comparePassword = function(candidate) {
  return bcrypt.compare(candidate, this.password);
};

module.exports = mongoose.model('User', userSchema);

¿Por qué cost 12? Balance entre seguridad y CPU. Ajusta según tu infraestructura.

Login: validar, firmar y enviar cookie

Regla: JWT corto (ej. 15–60 min) en cookie HttpOnly; refresh tokens aparte.

// controllers/auth.js (extracto)
const jwt = require('jsonwebtoken');

const login = async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });
  if (!user || !(await user.comparePassword(password))) {
    return res.status(401).json({ error: 'Credenciales inválidas' });
  }

  const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, { expiresIn: '15m' });

  res.cookie('authToken', token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict',
    maxAge: 15 * 60 * 1000
  });

  res.json({ success: true });
};

No pongas datos sensibles en el payload. Claims mínimos: userId y algún scope si hace falta.

Middleware protector de rutas

Intercepta y valida la cookie antes de permitir el acceso:

// middleware/auth.js
const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {
  const token = req.cookies.authToken;
  if (!token) return res.status(401).json({ error: 'No autorizado' });

  try {
    req.user = jwt.verify(token, process.env.JWT_SECRET);
    next();
  } catch (e) {
    res.status(401).json({ error: 'Token inválido o expirado' });
  }
};

Adjunta req.user.userId para consultas posteriores.

Logout: simple y efectivo

En una arquitectura basada en cookies HttpOnly, cerrar sesión es instructivo: borrar la cookie en el navegador.

// controllers/auth.js
const logout = (req, res) => {
  res.clearCookie('authToken', {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict'
  });
  res.json({ success: true });
};

Si necesitas invalidación inmediata de tokens (por ejemplo, forzar logout de todos los dispositivos), añade una lista de revocación en Redis con claves expiradas o guarda un tokenVersion en el usuario y compáralo en el JWT.

Comparativa: Cookies HttpOnly vs localStorage (resumen técnico)

  • Cookies HttpOnly: automáticas, resistentes a XSS, requieren SameSite y HTTPS.
  • localStorage: accesible por JS → vulnerable a XSS; menos recomendable para web.

Para la mayoría de SPAs web, cookies HttpOnly + CSRF mitigations (SameSite/CSRF token cuando sea necesario) es la opción correcta.

Consideraciones de producción (criterio senior)

  • Nunca expongas JWT_SECRET ni URIs en el repo; usa variables de entorno.
  • Usa HTTPS en todas partes; secure cookies dependen de ello.
  • Implementa rate limiting en /login (express-rate-limit).
  • Logging y alertas en intentos fallidos.
  • Considera refresh tokens almacenados en HttpOnly (o en un store) si necesitas sesiones largas. Documentación OWASP sobre autenticación: https://owasp.org.
  • Validación de entrada robusta (Joi o express-validator).

Conclusión y siguiente paso

Cree una API de inicio y cierre de sesión con Express.js (Node.js) usando JWT en cookies HttpOnly y bcrypt para contraseñas y habrás cubierto la base para una autenticación segura y escalable. Esto no es la cima: el siguiente paso es integrar refresh tokens seguros, rotación de tokens y estrategias de revocación (Redis/DB). Implementa lo básico bien y estarás listo para esas capas adicionales.

FAQ

Respuesta

Cookies HttpOnly no son accesibles desde JavaScript, lo que reduce la superficie de ataque frente a XSS. localStorage es accesible por JS y por tanto vulnerable a XSS.

Respuesta

Usa JWTs cortos (ej. 15–60 minutos) para access tokens. Para sesiones largas, combina con refresh tokens seguros y rotación de tokens.

Respuesta

Almacena refresh tokens en cookies HttpOnly o en un store con expiración. Implementa rotación: emite un nuevo refresh token al usar uno válido y revoca el anterior.

Respuesta

Para invalidación inmediata, usa una lista de revocación en Redis con claves expiradas o guarda un tokenVersion en el usuario y compáralo contra el JWT.

Respuesta

Automatizar hashing evita errores humanos (olvidar hashear antes de guardar) y estandariza el coste. Mongoose pre(‘save’) es una forma práctica de hacerlo.

Respuesta

Variables de entorno seguras, HTTPS obligatorio, rate limiting en endpoints críticos, logging/alertas, validación de input y mecanismos de revocación para tokens son esenciales.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *