Autenticación segura en TypeScript: guía para profesionales

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Tus datos en la mira: por qué la autenticación en TypeScript no es una broma

\n\n

Imagina: creaste una aplicación increíble en TypeScript. Vuela, los tipos son estrictos, el código es hermoso. Pero hay un pequeño detalle: la autenticación. Y aquí empieza lo interesante. Un error y los datos de los usuarios se escapan como agua entre los dedos. ¿Te suena?

\n\n

En 2024, la autenticación segura no es solo "poner un inicio de sesión". Es toda una ciencia. Y TypeScript aquí es tu mejor amigo. No te dejará pasar accidentalmente un tipo de dato incorrecto, te indicará dónde olvidaste verificar el token y te salvará de errores tontos durante la compilación.

\n\n

En este artículo, analizaremos cómo construir una autenticación segura en aplicaciones TypeScript desde cero. Sin rodeos: solo ejemplos reales, mejores prácticas y un poco de humor negro (no puede faltar).

\n\n

JWT: amor a primera vista con el token

\n\n

JSON Web Token (JWT) es el estándar de facto para la autenticación en aplicaciones web modernas. Pero, como decía el tío Ben, "un gran poder conlleva una gran responsabilidad". JWT puede ser tanto un escudo como una bomba de tiempo.

\n\n

Cómo NO hacerlo: anti-ejemplo

\n\n

El pecado más común de los principiantes es almacenar el token en localStorage y transmitirlo abiertamente. Sí, funciona. Pero es como dejar las llaves del departamento debajo del felpudo: es cómodo, pero cualquier transeúnte puede entrar. Un ataque XSS y todos tus tokens están en manos del atacante.

\n\n

Trabajo correcto con JWT en TypeScript

\n\n

Escribamos un envoltorio seguro para trabajar con tokens. TypeScript nos ayudará a no confundir los tipos y a no olvidar la validación.

\n\n
import jwt from 'jsonwebtoken';\n\ninterface TokenPayload {\n  userId: string;\n  role: 'user' | 'admin';\n  iat?: number;\n  exp?: number;\n}\n\n// Generamos el token con tipado claro\nfunction generateAccessToken(payload: TokenPayload): string {\n  return jwt.sign(\n    { ...payload },\n    process.env.JWT_SECRET as string,\n    { expiresIn: '15m' }\n  );\n}\n\n// Verificamos y casteamos inmediatamente a nuestra interfaz\nfunction verifyAccessToken(token: string): TokenPayload | null {\n  try {\n    return jwt.verify(\n      token, \n      process.env.JWT_SECRET as string\n    ) as TokenPayload;\n  } catch (error) {\n    console.error('El token no pasó la verificación:', error);\n    return null;\n  }\n}
\n\n

Observa: siempre verificamos que JWT_SECRET exista y sea una cadena. TypeScript nos obliga a hacerlo: ¡nada de undefined en tiempo de ejecución!

\n\n

Hash de contraseñas: bcrypt al rescate

\n\n

Almacenar contraseñas en texto plano es un delito. Incluso si tu base de datos está mejor protegida que Fort Knox, un solo ataque y aparecerás en las noticias como otro "filtrado de contraseñas". El hash de contraseñas es tu salvavidas.

\n\n

¿Por qué bcrypt y no MD5?

\n\n

MD5 está muerto. SHA-256 tampoco es una opción. Las GPU modernas pueden procesar miles de millones de hashes por segundo. Bcrypt, en cambio, está diseñado específicamente para ser lento. Usa sal (datos aleatorios) y un factor de costo ajustable. Cuanto mayor es el costo, más tiempo se tarda en calcular el hash. ¡Y eso es bueno!

\n\n

Implementación en TypeScript

\n\n
import bcrypt from 'bcrypt';\n\nconst SALT_ROUNDS = 12; // Valor óptimo en 2024\n\nasync function hashPassword(password: string): Promise<string> {\n  const salt = await bcrypt.genSalt(SALT_ROUNDS);\n  return bcrypt.hash(password, salt);\n}\n\nasync function comparePassword(\n  password: string, \n  hash: string\n): Promise<boolean> {\n  return bcrypt.compare(password, hash);\n}\n\n// Función tipada para el registro\ninterface CreateUserInput {\n  email: string;\n  password: string;\n  name: string;\n}\n\nasync function createUser(input: CreateUserInput): Promise<Omit<User, 'passwordHash'>> {\n  const passwordHash = await hashPassword(input.password);\n  \n  // Guardamos en la BD (aquí va tu c                

Blogs

Book Recommendations