Práctico

Autenticación y Admin

Configura roles de administrador de solo lectura y lectura/escritura, protege las APIs de admin y entiende el flujo de autenticación del template.

Autenticación y Admin

Este template usa Better Auth + Drizzle. El control de acceso (RBAC) se basa en la base de datos, sin elevación por variables de entorno.

Conceptos básicos: autenticación vs autorización

  • Autenticación: prueba quién eres (registro/inicio de sesión). El resultado es una sesión.
  • Autorización: decide qué puedes hacer después de iniciar sesión. Aquí lo controla el campo role en la tabla users.

Roles:

  • user — por defecto para todos.
  • admin_ro — solo lectura (ver datos de admin, sin escribir).
  • admin_rw — lectura + escritura (incluye otorgar créditos y otras acciones admin).

Una analogía sencilla

En un aeropuerto, mostrar tu identificación en seguridad es autenticación (probar identidad). Presentar la tarjeta de embarque en la puerta es autorización (verificar que puedes subirte a ese vuelo).

Comparación rápida

TemaAutenticaciónAutorización
PropósitoVerificar identidad (quién)Verificar permisos (qué)
MomentoAntes de la autorizaciónDespués de autenticación exitosa
Entradas típicasCredenciales (contraseña, enlace por email, social)Políticas/roles (user, admin_ro, admin_rw)
SalidaSesión/identidadAcciones permitidas y rutas protegidas
Estándares (generales)OIDC, ID TokensOAuth 2.0, scopes

En este template: usamos cookies de sesión HttpOnly en el servidor (no tokens en el front) y un rol en la BD para los checks de autorización.

¿Qué es Better Auth?

Una librería de auth ligera y orientada a TypeScript para Next.js.

  • Almacenamiento: Drizzle ORM + Postgres (ver src/lib/auth.ts).
  • Modelo de datos: users, sessions, accounts, verifications (ver src/db/schema.ts).
  • Sesiones: cookie HttpOnly y registro en sessions; las rutas del servidor leen la sesión con auth.api.getSession({ headers }).
  • Campos extra: exponemos uuid y role en la sesión vía additionalFields para facilitar validaciones en servidor.

Secretos y URLs (nivel inicial)

  • BETTER_AUTH_SECRET: secreto largo y aleatorio del servidor para firmar/verificar cookies/JSON Web Tokens. Genera una vez y mantenlo privado.
    • Generar: openssl rand -base64 32
    • Rotación: cambiarlo cierra la sesión de todos los usuarios (las sesiones previas dejan de ser válidas).
  • BETTER_AUTH_URL: base URL del servidor usada por la librería de auth (normalmente la URL del sitio).
  • NEXT_PUBLIC_AUTH_BASE_URL: base del lado del cliente (en la mayoría de casos, igual que la del sitio).
  • Cookies HttpOnly y secure en producción (ver advanced.defaultCookieAttributes en src/lib/auth.ts).

Si ves que la sesión se pierde tras reiniciar o solo funciona una vez, revisa estas variables y reinicia el servidor de dev.

Roles

  • user: por defecto.
  • admin_ro: solo lectura; puede listar usuarios, pedidos y ver créditos de un usuario.
  • admin_rw: lectura + operaciones; además puede otorgar créditos (trans_type = system_add).

La migración 0001_add_user_role.sql añade users.role con valor por defecto user.

Autorización

  • src/lib/authz.ts obtiene el rol desde la sesión/BD:
    • requireAdminRead() → permite admin_ro/admin_rw.
    • requireAdminWrite() → permite admin_rw.

Endpoints de Admin

  • GET /api/admin/users → lista de usuarios (paginación page, limit).
  • GET /api/admin/orders → pedidos pagados (paginación).
  • GET /api/admin/users/:uuid/credits → resumen de créditos.
  • POST /api/admin/credits/grant → otorga créditos como system_add.

Pasos de configuración

  1. Migrar BD:
pnpm drizzle-kit migrate --config src/db/config.ts
  1. Verificar endpoints (con una cuenta admin).

Cambiar roles

Usa la base de datos como fuente de verdad:

  • SQL:
    update users set role = 'admin_rw' where uuid = '<uuid>';
  • Helper de código:
    • updateUserRole(uuid, 'admin_ro' | 'admin_rw' | 'user') en src/models/user.ts.

Notas

  • Protege cuentas admin con MFA/SSO y sesiones más cortas.
  • Asegura páginas de admin en componentes de servidor y redirige si no hay permisos.
  • Los roles no se configuran por .env; cámbialos en la BD.

Inicio de sesión social (Google)

  • El proveedor está configurado en src/lib/auth.ts dentro de socialProviders.google y toma GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET de .env.
  • Asegúrate de definir: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, y también BETTER_AUTH_URL y NEXT_PUBLIC_AUTH_BASE_URL (por ejemplo http://localhost:3000 en desarrollo).
  • En Google Cloud Console → Credentials, añade la URI de redirección autorizada:
    • http://localhost:3000/api/auth/callback/google (dev)
    • https://tu-dominio.com/api/auth/callback/google (prod)
  • La pantalla /[locale]/login muestra un botón “Continuar con Google” que inicia el flujo OAuth.