DevPath · Aprende a programar ESPTEN

Autenticación y seguridad

Autorización: exigir token y comprobar roles

Autorizar es responder "¿puedes hacer esto?"

La autenticación dice quién eres; la autorización decide qué te está permitido. Son dos pasos distintos, y se reflejan en dos códigos de estado:

Un error muy común es devolver 401 cuando en realidad toca 403. Si el usuario ya está autenticado y simplemente le falta el permiso, es 403.

Middleware que exige un token válido

El primer middleware lee la cabecera Authorization. Si falta —o si el token no es válido porque la firma no cuadra— corta con 401. Si es válido, guarda el usuario en req.usuario para que los siguientes pasos sepan quién es.

function requiereAuth(req, res, next) {
  const cabecera = req.headers.authorization;
  // verificarToken devuelve el payload, o null si la firma no cuadra.
  const usuario = cabecera ? verificarToken(cabecera, SECRETO) : null;
  if (!usuario) {
    res.status(401).json({ error: "No autorizado" });
    return; // corta: no llama a next()
  }
  req.usuario = usuario;
  next();
}

En un caso real, la cabecera es "Bearer <token>": se separa el esquema (Bearer) del token antes de verificarlo. Para los ejercicios mandaremos el token directamente en la cabecera para centrarnos en la lógica.

Middleware de roles

La autorización por rol se resuelve con una fábrica de middleware: una función que recibe el rol exigido y devuelve el middleware concreto. Así puedes escribir requiereRol("admin") en cualquier ruta.

function requiereRol(rol) {
  return function (req, res, next) {
    if (!req.usuario || req.usuario.rol !== rol) {
      res.status(403).json({ error: "Sin permiso" });
      return;
    }
    next();
  };
}

Se encadenan en orden: primero requiereAuth (para que exista req.usuario), luego requiereRol("admin"):

app.delete("/usuarios/:id", requiereAuth, requiereRol("admin"), borrarUsuario);

Ejemplos

Encadenar autenticación y rol

function requiereRol(rol) {
  return function (req, res, next) {
    if (!req.usuario || req.usuario.rol !== rol) {
      res.status(403).json({ error: "Sin permiso" });
      return;
    }
    next();
  };
}

const soloAdmin = requiereRol("admin");
const req = { usuario: { rol: "lector" } };
const res = {
  status(c) { this.code = c; return this; },
  json(b) { console.log(this.code, JSON.stringify(b)); },
};
soloAdmin(req, res, () => console.log("acceso concedido"));
Pon esto en práctica

DevPath es un curso práctico: aquí lees la teoría; en la app la pones en práctica con ejercicios que se ejecutan de verdad, sin conexión.

Empezar gratis en la app →
← Autenticación: contraseñas y tokensSeguridad web: OWASP, CORS y buenas prácticas →