imansi-auth-node
v0.1.3
Published
Servidor de autenticación completo para Node.js: registro, login, 2FA, OAuth (GitHub y Google), sesiones multi-dispositivo y correos transaccionales.
Maintainers
Readme
imansi-auth-node
Servidor de autenticación completo para Node.js: registro, login, verificación en dos pasos (2FA), OAuth (GitHub y Google), sesiones multi-dispositivo, refresh tokens y correos transaccionales.
Parte del ecosistema Imansi — autenticación moderna para tus apps.
✨ Características
- Registro y login con email y contraseña (bcrypt).
- Verificación en dos pasos (2FA) por consola o email.
- OAuth con GitHub y Google (login social).
- Refresh tokens con rotación automática.
- Sesiones multi-dispositivo con revocación individual.
- Cookies httpOnly para máxima seguridad contra XSS.
- Recuperación de contraseña por correo electrónico.
- Cambio de contraseña estando logueado.
- Editar perfil (nombre).
- Correos transaccionales integrados con
imansi-correos-node(26 plantillas listas). - Rate limiting para evitar fuerza bruta.
- CLI integrado con verificación automática del sistema.
- JavaScript puro. Sin TypeScript, sin sorpresas.
- PostgreSQL como única dependencia de base de datos.
📦 Instalación
npm install imansi-auth-nodeTodas las dependencias vienen incluidas. No hace falta instalar nada más.
Requiere Node.js 18 o superior y PostgreSQL 12 o superior.
🚀 Uso rápido
1. Configurar el .env
Copiá el archivo de ejemplo:
cp node_modules/imansi-auth-node/.env.example .envY completá tus credenciales. Estas son todas las variables disponibles:
Servidor
PUERTO=3000
ENTORNO=desarrollo
URL_FRONTEND=http://localhost:5173
URL_BACKEND=http://localhost:3000PostgreSQL
PG_HOST=localhost
PG_PUERTO=5432
PG_USUARIO=postgres
PG_CONTRASENA=tu-contraseña
PG_BASE_DE_DATOS=miappJWT y cookies
JWT_SECRETO=generá-una-cadena-larga-y-aleatoria-aqui
JWT_EXPIRACION=15m
COOKIE_NOMBRE=sesion_autenticacion
COOKIE_SEGURA=false
COOKIE_MISMO_SITIO=lax
COOKIE_MAX_EDAD_SEGUNDOS=604800Refresh tokens
REFRESH_TOKENS_ACTIVADO=true
REFRESH_TOKEN_EXPIRACION_DIAS=3
REFRESH_TOKEN_ROTACION=true
COOKIE_REFRESH_NOMBRE=refresco_autenticacion
COOKIE_REFRESH_PATH=/auth
COOKIE_REFRESH_MISMO_SITIO=lax
COOKIE_REFRESH_SEGURA=falseVerificación en dos pasos (2FA)
DOS_FACTORES_ACTIVADO=false
DOS_FACTORES_FORMATO=numerico
DOS_FACTORES_LONGITUD=6
DOS_FACTORES_EXPIRACION_MINUTOS=5
DOS_FACTORES_MAX_INTENTOS=3
DOS_FACTORES_METODO=consolaOAuth
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_CALLBACK_URL=http://localhost:3000/auth/oauth/github/callback
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CALLBACK_URL=http://localhost:3000/auth/oauth/google/callback
OAUTH_VINCULAR_AUTOMATICO=trueCorreos
CORREOS_IMANSI_ACTIVADO=false
CORREOS_JSON=./correos.json
SMTP_HOST=
SMTP_PUERTO=587
SMTP_SEGURO=false
SMTP_USUARIO=
SMTP_CONTRASENA=
SMTP_REMITENTE=Mi App <[email protected]>Recuperación de contraseña
RECUPERACION_ACTIVADA=true
RECUPERACION_EXPIRACION_MINUTOS=30
RECUPERACION_URL_FRONTEND=http://localhost:5173/restablecer
RECUPERACION_CERRAR_SESIONES=trueGenerá un JWT_SECRETO seguro con:
node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"2. Verificar que todo esté bien
npx imansi-auth-node iniciarEse comando verifica:
- ✅ El
.envexiste y tiene las variables obligatorias. - ✅ PostgreSQL conecta correctamente.
- ✅ Las tablas están creadas (y te ofrece crearlas si no).
- ✅
imansi-correos-nodeestá instalado y el SMTP funciona.
3. Montar el servidor en tu app
// index.js
import express from "express";
import "dotenv/config";
import { crearServidorAutenticacion } from "imansi-auth-node";
const app = express();
// Tu app
app.get("/api/productos", (req, res) => res.json([...]));
// 🔐 Montar la autenticación
app.use("/", crearServidorAutenticacion());
app.listen(3000, () => {
console.log("Servidor en puerto 3000");
});Eso es todo. Con esas 4 líneas tenés todos los endpoints de autenticación funcionando.
🎯 Endpoints
Autenticación básica
| Método | Endpoint | Descripción |
| ----------------------------- | ----------------- | ------------------------------------- |
| POST | /auth/registro | Crea un usuario nuevo |
| POST | /auth/login | Inicia sesión |
| POST | /auth/logout | Cierra sesión |
| POST | /auth/refrescar | Renueva el access token |
| GET | /auth/usuario | Devuelve el usuario actual (o null) |
Verificación en dos pasos (2FA)
| Método | Endpoint | Descripción |
| ----------------------------- | --------------------- | --------------------------- |
| POST | /auth/verificar-2fa | Verifica el código recibido |
| POST | /auth/reenviar-2fa | Reenvía el código |
Recuperación de contraseña
| Método | Endpoint | Descripción |
| ----------------------------- | ------------------------------ | ------------------------------------------ |
| POST | /auth/solicitar-recuperacion | Envía un email con el link de recuperación |
| POST | /auth/restablecer-contrasena | Restablece la contraseña con el token |
Cuenta (logueado)
| Método | Endpoint | Descripción |
| ----------------------------- | -------------------------- | --------------------------- |
| POST | /auth/cambiar-contrasena | Cambia la contraseña actual |
| PATCH | /auth/perfil | Edita el nombre del usuario |
Sesiones
| Método | Endpoint | Descripción |
| ----------------------------- | -------------------- | ---------------------------- |
| GET | /auth/sesiones | Lista las sesiones activas |
| DELETE | /auth/sesiones/:id | Revoca una sesión específica |
OAuth
| Método | Endpoint | Descripción |
| ----------------------------- | ----------------------------- | ----------------------- |
| GET | /auth/oauth/github | Inicia OAuth con GitHub |
| GET | /auth/oauth/github/callback | Callback de GitHub |
| GET | /auth/oauth/google | Inicia OAuth con Google |
| GET | /auth/oauth/google/callback | Callback de Google |
Healthcheck
| Método | Endpoint | Descripción |
| ----------------------------- | -------- | ----------------------------------- |
| GET | /salud | Comprueba que el servidor esté vivo |
🔐 Verificación en dos pasos (2FA)
Activala en el .env:
DOS_FACTORES_ACTIVADO=true
DOS_FACTORES_METODO=consolaOpciones de DOS_FACTORES_METODO:
| Valor | Comportamiento |
| ----------------------- | ------------------------------------------------------- |
| consola | Imprime el código en la terminal (útil para desarrollo) |
| email | Envía el código por SMTP |
| auto | Consola en desarrollo, email en producción |
Cuando el 2FA está activado, el login devuelve:
{
"requiere2fa": true,
"idPendiente": "eyJhbGc..."
}Y el cliente debe llamar a /auth/verificar-2fa con ese idPendiente y el código.
Manejo de intentos: tras 3 fallos consecutivos, el código se invalida y el usuario debe reiniciar el login.
🔑 Recuperación de contraseña
El flujo completo:
- El usuario va a
/recuperary envía su correo. - El backend genera un token aleatorio (48 bytes) y lo hashea (SHA-256).
- Envía un correo con el link:
/restablecer?token=xxx. - El usuario hace clic y pone una contraseña nueva.
- El backend verifica el token, actualiza la contraseña y cierra todas las sesiones activas.
- Se envía un correo de aviso "contraseña cambiada".
Seguridad
- Rate limiting: máximo 3 solicitudes por usuario/hora.
- Expiración: 30 minutos por defecto.
- Un solo uso: el token se invalida tras usarse.
- No revela información: si el correo no existe, responde igual que si existiera.
- Solo aplica a usuarios con contraseña. Los usuarios solo-OAuth no reciben correo de recuperación.
Configuración
RECUPERACION_ACTIVADA=true
RECUPERACION_EXPIRACION_MINUTOS=30
RECUPERACION_URL_FRONTEND=http://localhost:5173/restablecer
RECUPERACION_CERRAR_SESIONES=true👤 Cambio de contraseña y perfil
Cambiar contraseña (logueado)
POST /auth/cambiar-contrasena
Content-Type: application/json
{
"contraseñaActual": "actual123",
"contraseñaNueva": "nueva456"
}- Verifica la contraseña actual.
- Actualiza el hash.
- Cierra todas las demás sesiones (excepto la actual).
- Envía un correo de aviso.
⚠️ Solo funciona para usuarios con contraseña. Los usuarios solo-OAuth no tienen contraseña que cambiar.
Editar perfil
PATCH /auth/perfil
Content-Type: application/json
{
"nombre": "Ivan Mansilla"
}🌐 OAuth (GitHub y Google)
Configurar GitHub
- Ve a github.com/settings/developers.
- Crea una OAuth App.
- Homepage URL:
http://localhost:5173 - Authorization callback URL:
http://localhost:3000/auth/oauth/github/callback - Copiá el Client ID y generá un Client Secret.
Pegalo en tu .env:
GITHUB_CLIENT_ID=tu_client_id
GITHUB_CLIENT_SECRET=tu_client_secret
GITHUB_CALLBACK_URL=http://localhost:3000/auth/oauth/github/callbackConfigurar Google
- Ve a console.cloud.google.com/apis/credentials.
- Crea un OAuth 2.0 Client ID (tipo "Aplicación web").
- Authorized JavaScript origins:
http://localhost:5173 - Authorized redirect URIs:
http://localhost:3000/auth/oauth/google/callback - Copiá el Client ID y el Client Secret.
Pegalo en tu .env:
GOOGLE_CLIENT_ID=tu_client_id
GOOGLE_CLIENT_SECRET=tu_client_secret
GOOGLE_CALLBACK_URL=http://localhost:3000/auth/oauth/google/callbackComportamiento
Cuando alguien se loguea con OAuth por primera vez:
- Se crea un usuario en tu base de datos (sin contraseña).
- Se vincula la cuenta de GitHub/Google.
- Se marca el correo como verificado.
- Se emite una sesión normal.
Si el correo ya existe como usuario local, se vincula automáticamente (configurable con OAUTH_VINCULAR_AUTOMATICO).
🔄 Refresh tokens
Activalos en el .env:
REFRESH_TOKENS_ACTIVADO=true
REFRESH_TOKEN_EXPIRACION_DIAS=3
REFRESH_TOKEN_ROTACION=true
JWT_EXPIRACION=15mCómo funcionan:
- El login emite dos tokens: un access token corto (15 min) y un refresh token largo (3 días).
- El access token viaja en una cookie httpOnly y se usa en cada petición.
- Cuando expira, el frontend llama a
/auth/refrescar. - El backend verifica el refresh token, lo rota (genera uno nuevo) y emite un nuevo access token.
- El usuario no nota nada.
📧 Correos con imansi-correos-node
El paquete viene con imansi-correos-node integrado. Trae 26 plantillas de correo listas para usar:
- Autenticación: 2FA, bienvenida, nueva sesión, sesión revocada.
- Contraseñas: recuperación, cambio.
- Verificación de correo: confirmación, cambio.
- Seguridad: cuenta bloqueada, inicio fallido.
- 2FA avanzado: activación, desactivación, códigos de respaldo.
- Transaccionales: notificación, contacto, encuesta, recordatorio.
- Comerciales: suscripción, recibo, factura, pago fallido, cancelación, plan, trial.
Activar los envíos reales
CORREOS_IMANSI_ACTIVADO=true
CORREOS_JSON=./correos.jsonY configurá el SMTP:
# Mailtrap (para pruebas)
SMTP_HOST=sandbox.smtp.mailtrap.io
SMTP_PUERTO=2525
SMTP_SEGURO=false
SMTP_USUARIO=tu_usuario
SMTP_CONTRASENA=tu_password
SMTP_REMITENTE=Mi App <[email protected]>Personalizar las plantillas
Creá un archivo correos.json en la raíz de tu proyecto:
{
"marca": {
"nombre": "Mi App",
"descripcion": "La mejor app del mundo",
"logo": { "url": "https://miapp.com/logo.png", "alto": 48, "ancho": "auto" },
"colores": {
"primario": "#0066cc",
"fondo": "#f4f4f4"
}
},
"remitente": {
"nombre": "Mi App",
"direccion": "[email protected]",
"responderA": "[email protected]"
},
"idioma": "es"
}Los colores, la marca, el logo y el idioma (es/en/pt) se aplican a todas las plantillas automáticamente.
Modo consola
Si dejás CORREOS_IMANSI_ACTIVADO=false, los códigos 2FA se imprimen en la consola del servidor en lugar de enviarse por email. Perfecto para desarrollo.
🛠️ CLI integrado
El paquete incluye un CLI para verificar y administrar la instalación.
Verificar el sistema
npx imansi-auth-node iniciarWizard interactivo que verifica los 8 puntos críticos: .env, variables obligatorias, PostgreSQL, tablas, imansi-correos-node, SMTP, correos.json, y la conexión completa.
Correr migraciones
npx imansi-auth-node migrarCrea todas las tablas necesarias si no existen.
Reiniciar la base de datos
npx imansi-auth-node reiniciar⚠️ Destructivo. Borra TODAS las tablas y las vuelve a crear. Solo para desarrollo. Pide confirmación escribiendo BORRAR.
Ver la ayuda
npx imansi-auth-node --help🧩 Uso avanzado
Solo rutas, sin servidor completo
Si ya tenés una app Express y solo querés las rutas de auth:
import express from "express";
import { crearRutasAutenticacion } from "imansi-auth-node";
const app = express();
app.use(crearRutasAutenticacion());Proteger tus propias rutas
import { requerirAutenticacion } from "imansi-auth-node";
app.get("/api/perfil", requerirAutenticacion(), (req, res) => {
// req.usuario está disponible
res.json(req.usuario);
});Usar los servicios sin el servidor HTTP
import {
crearUsuario,
validarCredenciales,
firmarToken,
buscarPorId
} from "imansi-auth-node";
const usuario = await crearUsuario({
nombre: "Ivan",
correo: "[email protected]",
contrasena: "secreto123"
});Configuración personalizada
Todo lo que está en el .env se puede sobrescribir en código:
import { crearServidorAutenticacion } from "imansi-auth-node";
app.use(
"/auth",
crearServidorAutenticacion({
cookie: {
mismoSitio: "none",
segura: true
},
dosFactores: {
activado: true,
metodo: "email"
},
oauth: {
github: {
clientId: "...",
clientSecret: "..."
}
}
})
);📚 API pública
Servidor y rutas
crearServidorAutenticacion(config?)→ App de Express lista para montar.crearRutasAutenticacion(config?)→ Solo el Router de auth.crearRutasOAuth(config?)→ Solo el Router de OAuth.
Middlewares
requerirAutenticacion(config?)→ Bloquea con 401 si no hay sesión.cargarUsuarioOpcional(config?)→ Carga el usuario si hay sesión, sigue si no.
Configuración
crearConfiguracion(config?)→ Fusiona la config con los valores por defecto.configuracionPorDefecto→ Objeto con los valores por defecto.
Base de datos
ejecutarMigraciones()→ Crea las tablas (idempotente).reiniciar()→ Borra y recrea todas las tablas.cerrarPool()→ Cierra el pool de conexiones.
Servicios individuales
- Usuarios:
crearUsuario,buscarPorCorreo,buscarPorId,validarCredenciales,crearUsuarioDesdeOAuth,marcarCorreoVerificado,actualizarNombre,actualizarContrasena,verificarContrasenaActual. - Tokens:
firmarToken,verificarToken. - 2FA:
crearCodigoDosFactores,verificarCodigoDosFactores. - Recuperación:
crearTokenRecuperacion,verificarTokenRecuperacion,consumirTokenRecuperacion.
Re-export de imansi-correos-node
Todo lo de imansi-correos-node está disponible:
import { correos } from "imansi-auth-node";
const correo = correos.correoNotificacionGenerica({...});
await correos.enviarCorreo(correo);🔒 Seguridad
El paquete aplica varias capas de seguridad por defecto:
- Contraseñas con bcrypt (10 rondas).
- Cookies httpOnly + SameSite → el token no es accesible desde JavaScript.
- Rate limiting para evitar fuerza bruta.
- CORS restringido al frontend que configures.
- Helmet para cabeceras HTTP seguras.
- JWT firmados con el secreto que definas.
- Refresh tokens hasheados en base de datos.
- Revocación individual de sesiones.
- Recuperación de contraseña con tokens hasheados (SHA-256).
- Cierre de sesiones al cambiar la contraseña.
Para producción
ENTORNO=produccion
COOKIE_SEGURA=true
COOKIE_MISMO_SITIO=none
COOKIE_REFRESH_SEGURA=true
JWT_SECRETO=una-cadena-larga-y-única-de-48-bytes-o-más⚠️ Nunca subas el .env a Git. Agregalo a .gitignore.
🌍 Multi-idioma
Los correos soportan 3 idiomas: es, en, pt. Se configura en correos.json:
{ "idioma": "es" }🧬 Ecosistema Imansi
imansi-auth-node— Este paquete (backend).imansi-correos-node— 26 plantillas de correo.imansi-auth-react— Componentes frontend para React (próximamente).
Todos comparten el mismo contrato HTTP y los mismos nombres en español.
🛠️ Desarrollo
Clonar y probar localmente
git clone https://github.com/imansi-pro/imansi-auth-node.git
cd imansi-auth-node
npm install
npm run devScripts disponibles
| Script | Qué hace |
| ------------------- | ---------------------------------------- |
| npm run dev | Arranca con nodemon (recarga automática) |
| npm start | Arranca el servidor en producción |
| npm run migrar | Crea las tablas |
| npm run reiniciar | Borra y recrea las tablas |
Estructura del proyecto
imansi-auth-node/
├── bin/
│ └── cli.js ← CLI (npx imansi-auth-node)
├── src/
│ ├── baseDeDatos/ ← Pool, migraciones, reinicio
│ ├── cli/ ← Lógica del CLI
│ ├── configuracion/ ← Config por defecto
│ ├── controladores/ ← Handlers HTTP
│ ├── middlewares/ ← Auth, errores, seguridad
│ ├── rutas/ ← Routers de Express
│ ├── servicios/ ← Lógica de negocio
│ ├── utilidades/ ← Helpers
│ └── index.js ← Punto de entrada
├── .env.example
├── LICENSE
├── package.json
└── README.md📦 Verificar el contenido del paquete
Antes de publicar, verificá que el paquete tenga:
- ✅
LICENSE - ✅
.npmignore - ✅
README.md - ✅
package.jsonconbin,files,exports - ✅
bin/cli.js - ✅
src/cli/completo - ✅
.env.example
Ejecutá:
npm pack --dry-runDebería mostrar una lista limpia con:
bin/cli.jssrc/completoREADME.mdLICENSE.env.examplepackage.json
Sin node_modules, sin .env, sin pruebas/, sin correos.json.
📄 Licencia
MIT © 2026 Ivan Mansilla
💬 Soporte
- Documentación: docs.imansi.pro
- Issues: github.com/imansi-pro/imansi-auth-node/issues
- Email: [email protected]
