Nunca guardes contraseñas en claro
Guarda siempre el hash de la contraseña, no la contraseña. Y no cualquier hash: usa uno lento y con sal pensado para esto, como bcrypt, scrypt o argon2.
- Sal (salt): un valor aleatorio único por usuario que se mezcla antes de hashear. Hace que dos personas con la misma contraseña tengan hashes distintos y rompe los ataques con tablas precalculadas (rainbow tables).
- Lento a propósito: bcrypt es costoso de calcular, lo que frena los ataques de fuerza bruta.
contraseña + sal ──bcrypt──> $2b$10$N9qo8uLOick... (esto es lo que guardas)
En el login, vuelves a hashear lo que escribe el usuario y comparas hashes; nunca recuperas la contraseña original (no se puede, y eso es bueno).
Otras reglas de oro
- HTTPS siempre: sin TLS, cualquiera en la red puede leer el token o la contraseña en tránsito. La credencial viaja en claro sin él.
- No metas secretos en el payload del token: recuerda, es legible por cualquiera. Nada de contraseñas ni datos sensibles dentro del JWT.
- Caducidad corta + refresh: access tokens de vida breve y un refresh token para renovar. Reduce la ventana de daño si roban un token.
- Logout y revocación: un JWT stateless no se puede "borrar" del cliente, así que para revocarlo de verdad mantienes una lista de revocación (o invalidas el refresh token) en el servidor. Las sesiones, en cambio, se revocan simplemente borrándolas del almacén.
- Cookies seguras: si usas cookies, márcalas
httpOnly,SecureySameSitepara mitigar XSS y CSRF a la vez.
Ejemplos
Verificar caducidad: comparar exp con el momento actual
const ahora = Math.floor(Date.now() / 1000);
const payload = { sub: "ana", exp: ahora - 60 }; // caducó hace 1 minuto
console.log(payload.exp < ahora ? "caducado" : "válido");