OAuth 2.0 y autorización JWT en TypeScript: guía práctica

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

Introducción: por qué OAuth 2.0 y JWT son el estándar de la autorización moderna

\n

En el desarrollo web moderno, la autenticación y autorización seguras son componentes críticos de cualquier aplicación. OAuth 2.0 y JWT (JSON Web Tokens) se han convertido en el estándar de facto para construir sistemas distribuidos. OAuth 2.0 proporciona un protocolo de acceso delegado, mientras que JWT es un formato de token compacto y autónomo.

\n

En este artículo, con ejemplos prácticos en TypeScript, analizaremos cómo implementar el ciclo completo de autorización: desde la emisión de tokens hasta su validación y renovación. Aprenderá cómo proteger endpoints de API, implementar refresh tokens y manejar errores típicos.

\n\n

1. Configuración básica del proyecto e instalación de dependencias

\n

Para empezar, crearemos un proyecto en Node.js con TypeScript. Asegúrese de tener instalados Node.js (versión 18+) y npm.

\n
mkdir oauth-jwt-typescript\ncd oauth-jwt-typescript\nnpm init -y\nnpm install express cors dotenv jsonwebtoken bcrypt\nnpm install -D typescript @types/express @types/cors @types/jsonwebtoken @types/bcrypt ts-node nodemon\nnpx tsc --init
\n

Configuraremos tsconfig.json para trabajar con módulos ES y tipos estrictos. En el archivo .env agregaremos las claves secretas:

\n
ACCESS_TOKEN_SECRET=your-super-secret-access-key\nREFRESH_TOKEN_SECRET=your-super-secret-refresh-key\nACCESS_TOKEN_EXPIRES_IN=15m\nREFRESH_TOKEN_EXPIRES_IN=7d
\n\n

2. Implementación de generación y verificación de tokens JWT

\n

Crearemos una utilidad src/utils/jwt.ts para trabajar con tokens. Usaremos dos tipos de tokens: Access Token (de corta duración) y Refresh Token (de larga duración).

\n
import jwt from 'jsonwebtoken';\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\ninterface TokenPayload {\n  userId: string;\n  email: string;\n  role: 'user' | 'admin';\n}\n\nexport const generateAccessToken = (payload: TokenPayload): string => {\n  return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET!, {\n    expiresIn: process.env.ACCESS_TOKEN_EXPIRES_IN || '15m',\n  });\n};\n\nexport const generateRefreshToken = (payload: TokenPayload): string => {\n  return jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET!, {\n    expiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN || '7d',\n  });\n};\n\nexport const verifyAccessToken = (token: string): TokenPayload => {\n  return jwt.verify(token, process.env.ACCESS_TOKEN_SECRET!) as TokenPayload;\n};\n\nexport const verifyRefreshToken = (token: string): TokenPayload => {\n  return jwt.verify(token, process.env.REFRESH_TOKEN_SECRET!) as TokenPayload;\n};
\n

Tenga en cuenta: usamos tipado estricto para el payload. Esto garantiza que el token siempre contendrá los campos necesarios.

\n\n

3. Creación de middleware para proteger rutas

\n

Ahora implementaremos un middleware que verificará la presencia y validez del Access Token en el encabezado Authorization. Crearemos src/middleware/auth.ts:

\n
import { Request, Response, NextFunction } from 'express';\nimport { verifyAccessToken } from '../utils/jwt';\n\nexport interface AuthRequest extends Request {\n  user?: {\n    userId: string;\n    email: string;\n    role: 'user' | 'admin';\n  };\n}\n\nexport const authenticate = (req: AuthRequest, res: Response, next: NextFunction): void => {\n  const authHeader = req.headers['authorization'];\n  const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN\n\n  if (!token) {\n    res.status(401).json({ error: 'Access token is required' });\n    return;\n  }\n\n  try {\n    const decoded = verifyAccessToken(token);\n    req.user = decoded;\n    next();\n  } catch (error) {\n    res.status(403).json({ error: 'Invalid or expired access token' });\n  }\n};\n\nexport const authorizeRole = (...roles: string[]) => {\n  return (req: AuthRequest, res: Response, next: NextFunction): void => {\n    if (!req.user || !roles                

Blogs

Book Recommendations