Ir al contenido

Autenticación

Decisión Opción
Librería NextAuth v5 (next-auth@beta)
Providers Google OAuth (GitHub planificado)
Adapter @auth/prisma-adapter + Prisma 7
Estrategia JWT (por defecto)
Base de datos Neon PostgreSQL (cloud) / Local Docker
lib/
├── auth/
│ ├── auth.ts ← Configuración de NextAuth (providers, adapter, callbacks)
│ └── client.ts ← Re-export de signIn / signOut para componentes cliente
├── prisma.ts ← Singleton de PrismaClient con adapter PrismaPg
Archivo Propósito
lib/auth/auth.ts Configuración central de NextAuth (Google provider, PrismaAdapter, JWT strategy)
lib/auth/client.ts Wrapper de signIn/signOut de next-auth/react
lib/prisma.ts Singleton PrismaClient con PrismaPg adapter
app/api/auth/[...nextauth]/route.ts API route de NextAuth (GET/POST)
middleware.ts Solo next-intl (sin auth en edge runtime)
# .env — defaults compartidos (gitignored)
DATABASE_URL="postgresql://syncro:syncro@localhost:5432/syncro?schema=public"
AUTH_URL="http://localhost:3000"
# .env.local — secretos (gitignored)
AUTH_SECRET="..."
AUTH_GOOGLE_ID="..."
AUTH_GOOGLE_SECRET="..."

En Vercel → Project Settings → Environment Variables, añadir:

DATABASE_URL="postgresql://neondb_owner:...@ep-xxx.eu-west-2.aws.neon.tech/neondb?sslmode=require"
AUTH_URL="https://syncro.vercel.app"
AUTH_SECRET="..."
AUTH_GOOGLE_ID="..."
AUTH_GOOGLE_SECRET="..."

En Google Cloud Console → Credenciales → OAuth 2.0 Client ID, los Authorized redirect URIs deben incluir:

http://localhost:3000/api/auth/callback/google
https://syncro.vercel.app/api/auth/callback/google
  1. Usuario hace clic en “Google” en login/register
  2. signIn("google", { redirectTo: "/home" }) redirige a Google
  3. Google redirige a /api/auth/callback/google
  4. NextAuth recibe el código, intercambia por tokens, crea/encuentra usuario en DB
  5. Sesión JWT creada, redirige a /home (sin locale)
  6. Middleware de next-intl detecta cookie NEXT_LOCALE y redirige a /[locale]/home
  • El middleware de next-intl setea la cookie NEXT_LOCALE al visitar cualquier página
  • Google OAuth redirige a /home (sin prefijo de locale)
  • El middleware lee la cookie y completa la ruta: /es/home o /en/home
Decisión Motivo
NextAuth vs Lucia/Clerk Integración nativa con Prisma, OAuth out-of-the-box
JWT strategy vs database sessions Más simple para solo OAuth
SessionProvider separado El layout [locale] es servidor; SessionProvider necesita ser cliente
Sin auth en middleware Prisma falla en edge runtime
redirectTo: "/home" Separar landing (pública) de dashboard (autenticada)

La URL de callback no está registrada en Google Cloud Console.

Fix: Agregar la URL completa en Google Cloud Console → Credenciales → OAuth 2.0 Client ID → “Authorized redirect URIs”.

Para local: http://localhost:3000/api/auth/callback/google Para producción: https://syncro.vercel.app/api/auth/callback/google

Autenticación con credentials (email + contraseña)

Sección titulada «Autenticación con credentials (email + contraseña)»

Además de Google OAuth, la aplicación soporta registro e inicio de sesión con email y contraseña mediante el Credentials provider de NextAuth.

Nota histórica: durante el desarrollo inicial, el Credentials provider devolvía un usuario de desarrollo hardcodeado (dev@syncro.app) para que el flujo de login funcionara sin base de datos real. Actualmente se validan credenciales reales contra la base de datos.

Archivo Propósito
lib/auth/auth.ts Configuración del Credentials provider y callbacks de NextAuth
server/user/actions/user-actions.ts Server action registerAccountAction con validación de Zod
server/user/service/user-service.ts registerUser y verifyCredentials (hashing y verificación)
server/user/repository/user-repository.ts Acceso a base de datos para usuarios
server/workspace/service/workspace-service.ts Creación del workspace personal
app/[locale]/(auth)/register/page.tsx Formulario de registro con auto-login
app/[locale]/(auth)/login/page.tsx Formulario de login
Decisión Motivo
bcryptjs para hashing No requiere compilación nativa, funciona en Windows sin herramientas adicionales y es suficiente para el MVP
Hashing en la capa de servicio Mantiene la lógica de negocio fuera de la UI y las server actions
Sin verificación de email Se omite en el MVP para agilizar el flujo de desarrollo. En producción se debería añadir verificación por email o magic links
Auto-login tras registro Después de crear la cuenta, el cliente llama a signIn("credentials") automáticamente para evitar un paso extra al usuario
Normalización de email email.toLowerCase().trim() antes de consultar o guardar en base de datos
  1. El usuario rellena el formulario de registro.
  2. La server action valida los datos con Zod v4.
  3. Si la validación pasa, se llama a registerUser en el servicio.
  4. registerUser hashea la contraseña y crea el usuario dentro de una transacción de Prisma.
  5. En la misma transacción se crea un workspace personal para el usuario.
  6. Si todo sale bien, el cliente hace auto-login con las credenciales recién creadas.

La server action registerAccountAction usa Zod para validar:

  • name: no vacío, máximo 100 caracteres
  • email: formato válido
  • password: mínimo 8 caracteres
  • confirmPassword: debe coincidir con password

Los errores de Zod se mapean a códigos (INVALID_EMAIL, PASSWORD_TOO_SHORT, etc.) que el cliente traduce a través de next-intl. Esto mantiene el schema puro y desacoplado de los mensajes de UI.

  • No hay rate limiting en login/register. Se recomienda añadirlo antes de producción.
  • No hay verificación de email. Cualquier email válido puede registrarse sin confirmar.
  • La fortaleza de la contraseña solo valida longitud mínima. En producción se debería exigir mayúsculas, números o símbolos.
  • Email enumeration: el mensaje de error para email duplicado es genérico (REGISTRATION_FAILED) para no revelar si un email ya está registrado.
  • GitHub OAuth provider
  • Verificación de email (confirmación por correo o magic link)
  • Rate limiting para login/register
  • Role-based access control (admin, member)
  • Magic link (email sin contraseña)
  • Fortalecer reglas de contraseña (mayúsculas, números, símbolos)