API REST con Express y TypeScript, arquitectura por capas (similar a NestJS) y autenticación JWT con refresh tokens. Documentación OpenAPI (Swagger) en /api-docs.
authentication-example/
├── prisma/ # Schema y migraciones Prisma
├── src/
│ ├── core/ # Config, middleware, utils, types
│ │ ├── config/ # CORS, database
│ │ ├── middleware/ # Auth, error handler, 404
│ │ ├── types/
│ │ └── utils/ # JWT, pagination
│ ├── modules/
│ │ ├── auth/ # Registro, login, refresh, logout, profile
│ │ └── user/ # CRUD usuarios
│ ├── app.ts # App Express y rutas
│ ├── index.ts # Entrada
│ └── openapi.ts # Especificación OpenAPI
├── package.json
└── tsconfig.json
- Node.js 18+
- PostgreSQL
- npm o pnpm
- Clonar e instalar dependencias:
npm install- Variables de entorno: copiar
.env.examplea.envy ajustar:
NODE_ENV=development
DATABASE_URL="postgresql://usuario:password@localhost:5432/nombre_bd"
JWT_SECRET=tu_secreto_super_seguro_minimo_32_caracteres
JWT_ACCESS_TOKEN_EXPIRES_IN=15m
JWT_REFRESH_TOKEN_EXPIRES_IN=7d
# Opcional (default 12)
BCRYPT_ROUNDS=12JWT_SECRET aleatorio de al menos 32 caracteres.
- Generar cliente Prisma:
npm run prisma:generate- Aplicar migraciones (crea/actualiza tablas):
npm run prisma:migrate -- initPara migraciones posteriores, usa un nombre descriptivo: npm run prisma:migrate -- nombre_cambio.
npm run devnpm run build
npm startnpm run prisma:studioCon el servidor en marcha: http://localhost:3000/api-docs
Base URL: http://localhost:3000/api
| Método | Ruta | Auth | Descripción |
|---|---|---|---|
| GET | /health |
No | Estado del servidor |
| POST | /auth/register |
No | Registrar usuario |
| POST | /auth/login |
No | Login |
| POST | /auth/refresh |
No | Refrescar access token |
| POST | /auth/logout |
Sí | Cerrar sesión |
| GET | /auth/profile |
Sí | Perfil del usuario autenticado |
| GET | /users |
Sí | Listar usuarios (paginado) |
| GET | /users/:id |
Sí | Usuario por ID |
| POST | /users |
Sí | Crear usuario |
| PUT | /users/:id |
Sí | Actualizar usuario |
| DELETE | /users/:id |
Sí | Eliminar usuario |
Rutas protegidas: header Authorization: Bearer <access_token>.
Registro POST /api/auth/register:
{
"email": "[email protected]",
"password": "contraseña123",
"name": "Nombre",
"username": "usuario"
}username es opcional; si no se envía, se usa la parte antes de @ del email.
Login POST /api/auth/login:
{
"email": "[email protected]",
"password": "contraseña123"
}Refresh POST /api/auth/refresh: body opcional { "refreshToken": "..." } o cookie refreshToken.
- Registro/Login: se devuelve
accessToken(corto) yrefreshToken(largo). El refresh puede enviarse por cookie httpOnly o en el body. - Rutas protegidas: header
Authorization: Bearer <access_token>. - Renovación: cuando expire el access token, usar
POST /api/auth/refreshcon el refresh token. - Logout: invalida el refresh token en servidor y opcionalmente limpia cookies.
# Registro
curl -X POST http://localhost:3000/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password123","name":"User","username":"user"}'
# Login
curl -X POST http://localhost:3000/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","password":"password123"}'
# Perfil (sustituir TOKEN)
curl -X GET http://localhost:3000/api/auth/profile \
-H "Authorization: Bearer TOKEN"
# Refresh
curl -X POST http://localhost:3000/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refreshToken":"REFRESH_TOKEN"}'
# Logout
curl -X POST http://localhost:3000/api/auth/logout \
-H "Authorization: Bearer TOKEN"- Contraseñas con bcrypt (12 rounds por defecto).
- Access token de corta duración; refresh token de larga duración.
- Refresh tokens guardados en BD para invalidación en logout.
- Cookies httpOnly para refresh token (mitigación XSS).
- Validación de email y contraseña (mínimo 8 caracteres).
- Middleware de autenticación en rutas protegidas.
- No se exponen passwords ni refresh tokens en respuestas.
- Runtime: Node.js
- Framework: Express 5
- Lenguaje: TypeScript
- ORM: Prisma
- Base de datos: PostgreSQL
- Auth: JWT (jsonwebtoken) + bcrypt
- Docs: OpenAPI 3 + Swagger UI
model Users {
id String @id @default(cuid())
email String @unique
name String @unique
username String @unique
password String
refreshToken String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}JWT_SECRETaleatorio y seguro (≥ 32 caracteres).- Usar HTTPS.
- Ajustar CORS al dominio del frontend.
- Valorar rate limiting en login/register.
- Logging de intentos de autenticación fallidos.