Documentación

Better Auth

Cómo Motoko Base gestiona la autenticación con Better Auth — email/contraseña, OAuth, sesiones, rutas protegidas, verificación y gestión de cuenta.

Abrir enChatGPT (se abre en una pestaña nueva)Claude (se abre en una pestaña nueva)Cursor (se abre en una pestaña nueva)Cómo Motoko Base gestiona la autenticación con Better Auth — email/contraseña, OAuth, sesiones, rutas protegidas, verificación y gestión de cuenta.

Motoko Base usa Better Auth para la autenticación. Las sesiones se almacenan en PostgreSQL mediante el adaptador Drizzle. No hay un servicio de auth aparte — Postgres más las variables de entorno bastan para el desarrollo local.

Las rutas de la API de auth están montadas en /api/auth/*. El dashboard requiere una sesión verificada antes de renderizar.

Qué incluye de fábrica

FeatureStatusNotes
Email / password sign-upEnabledVerification required before dashboard access
Email / password sign-inEnabledRedirects unverified users to /verify-email
Google OAuthOptionalEnabled when GOOGLE_* env vars are set
GitHub OAuthOptionalEnabled when GITHUB_* env vars are set
Email verificationRequiredSent on sign-up; resend on sign-in if still unverified
Password resetEnabledRequires Resend (RESEND_API_KEY, EMAIL_FROM)
Change passwordEnabledSettings → Security; revokes other sessions
Sign outEnabledUser menu in the dashboard header
Session managementEnabledList and revoke sessions in Settings → Security
Account linkingEnabledGoogle and GitHub link to the same user when trusted

Los botones de inicio de sesión social permanecen deshabilitados hasta que se configuren las credenciales OAuth. Consulta Configuración OAuth para el setup paso a paso de cada proveedor.

Email y contraseña

Sign up (/sign-up) recoge nombre, email y contraseña. Better Auth crea el usuario y envía un email de verificación cuando Resend está configurado.

Como requireEmailVerification está activo, el registro no inicia sesión automáticamente. Tras registrarse ven una pantalla de “Check your email” y deben verificar antes de acceder a /dashboard.

Sign in (/sign-in) acepta email y contraseña. En caso de éxito, el cliente redirige a /dashboard. Si el email no está verificado, Better Auth devuelve 403 EMAIL_NOT_VERIFIED y el formulario redirige a /verify-email.

Las reglas de contraseña para registro y cambio de contraseña se validan en src/features/dashboard/schemas/security.ts (MIN_PASSWORD_LENGTH = 8 por defecto).

OAuth de Google y GitHub

Ambos proveedores están cableados en src/lib/auth/auth.ts y solo se activan cuando las variables de entorno están presentes. El cliente usa authClient.signIn.social({ provider: "google" | "github" }) desde los formularios de sign-in y sign-up.

Los usuarios OAuth suelen quedar marcados como verificados por el proveedor. El account linking está habilitado para Google y GitHub para que un usuario social que vuelve pueda vincularse a una cuenta de email existente cuando Better Auth confía en el proveedor.

Setup completo del proveedor: Configuración OAuth.

Sesiones

Las sesiones se almacenan en la tabla session (src/lib/db/schema/auth.ts). Cada sesión tiene token, caducidad, IP y user agent.

Lecturas en el servidor usan getCachedSession() de src/lib/auth/session.ts. Envuelve auth.api.getSession() en React cache() para que layout, páginas y server actions de la misma petición compartan una sola consulta.

Llamadas en el cliente usan authClient de src/lib/auth/client.ts (cliente React de Better Auth).

Ejemplo — comprobar la sesión en un server component o action:

import { getCachedSession } from "@/lib/auth/session";

const session = await getCachedSession();
if (!session?.user?.id) {
  // not signed in
}

Rutas protegidas

Las rutas del dashboard bajo /dashboard están protegidas en dos capas:

  1. src/proxy.ts — puerta en el edge para /dashboard y /dashboard/*. Redirige usuarios no autenticados a /sign-in y no verificados a /verify-email.
  2. src/app/dashboard/layout.tsx — layout del servidor que repite las mismas comprobaciones antes de renderizar el shell.

Las páginas individuales y server actions también llaman a getCachedSession() y redirigen o devuelven errores cuando hace falta. Este patrón de defensa en profundidad mantiene seguras las rutas API y actions aunque una página olvide comprobar.

Para proteger una ruta nueva, colócala bajo src/app/dashboard/ (hereda layout + proxy) o llama a getCachedSession() y redirige manualmente.

Verificación de email

La verificación es obligatoria para acceder al dashboard.

StepWhat happens
Sign upBetter Auth sends a verification link via sendVerificationEmail
Click linkUser is verified; they can sign in
Unverified sign-inRedirect to /verify-email
Resend/verify-email calls authClient.sendVerificationEmail

La entrega de email requiere RESEND_API_KEY y EMAIL_FROM. Sin Resend, la app arranca pero no se envían emails de verificación — configura el email antes de probar el registro en local.

El contenido del email de verificación vive en src/lib/email/templates/verification-email.tsx. El hook de envío está en src/lib/auth/auth.ts bajo emailVerification.sendVerificationEmail.

Restablecimiento de contraseña

RoutePurpose
/forgot-passwordRequest a reset link
/reset-password?token=…Set a new password from the email link

Flujo:

  1. El usuario envía el email en /forgot-password
  2. El cliente llama a authClient.requestPasswordReset con redirectTo apuntando a /reset-password
  3. Better Auth envía el email vía sendResetPassword en auth.ts
  4. El usuario abre el enlace y envía una contraseña nueva vía authClient.resetPassword

Los emails de reset requieren Resend. La página de forgot-password comprueba la configuración de email antes de enviar.

Cambiar contraseña

Los usuarios autenticados cambian su contraseña en Settings → Security (/dashboard/settings/account/security).

La UI llama a updatePasswordAction en src/features/dashboard/actions/security.ts, que usa auth.api.changePassword con revokeOtherSessions: true — el resto de dispositivos se cierran tras un cambio correcto.

Los límites de longitud de contraseña vienen de src/features/dashboard/schemas/security.ts.

Cerrar sesión

El cierre de sesión se dispara desde el menú de usuario del dashboard. src/features/dashboard/components/dashboard-shell.tsx llama:

await authClient.signOut({
  fetchOptions: {
    onSuccess: () => {
      router.push("/sign-in");
      router.refresh();
    },
  },
});

El contexto de usuario de Analytics y Sentry se limpia al cerrar sesión en el mismo handler.

Gestión de cuenta y sesiones

Profile (nombre, avatar) — Settings → Profile (src/features/dashboard/components/settings/profile-settings-page.tsx).

Security (contraseña, sesiones) — Settings → Security:

  • Cambiar contraseña
  • Listar sesiones activas (navegador, SO, última actividad)
  • Revocar sesiones individuales
  • Cerrar sesión en todos los demás dispositivos

La lógica de servidor está en src/features/dashboard/actions/security.ts (updatePasswordAction, revokeSessionAction (sessions load via src/features/dashboard/lib/security-settings.ts)).

Al registrarse, se envía un email de bienvenida desde el hook databaseHooks.user.create.after en auth.ts. Cuando Polar billing está configurado, el plugin Polar de Better Auth crea un cliente de facturación al registrarse (src/lib/billing/providers/polar/auth-plugin.ts).


¿Dónde cambio esto?

Motoko Base reparte la auth entre infraestructura de servidor (src/lib/auth/), páginas de auth (src/app/…) y ajustes de cuenta (src/features/dashboard/components/settings/). No hay una carpeta src/features/auth/ aparte — la UI de auth vive en las rutas de app; la gestión de cuenta vive en settings.

src/lib/auth/ — núcleo de auth en el servidor

FileChange this when you want to…
auth.tsEnable/disable providers, toggle verification, customize email hooks, add Better Auth plugins, change account linking
session.tsAdjust how server components read the session (getCachedSession)
client.tsConfigure the browser auth client (base URL is inferred automatically)
social.tsChange how Google/GitHub “configured” checks work
safe-client-error.tsEdit user-facing error messages for sign-in, sign-up, OAuth

El handler catch-all de la API es src/app/api/auth/[...all]/route.ts — rara vez necesitas editarlo.

Tablas de base de datos: src/lib/db/schema/auth.ts (user, session, account, verification).

Páginas de auth — sign-in, sign-up, recuperación

PathChange this when you want to…
src/app/sign-in/Sign-in form behavior, post-login redirect, OAuth handlers
src/app/sign-up/Sign-up form, pending-verification UI
src/app/verify-email/Resend verification UX
src/app/forgot-password/Forgot-password form
src/app/reset-password/Reset-password form
src/components/ui/auth-section-3.tsxShared auth layout (fields, social buttons, styling)

Las páginas de sign-in y sign-up pasan googleEnabled / githubEnabled desde isGoogleAuthConfigured() e isGitHubAuthConfigured() para que los botones se deshabiliten automáticamente cuando OAuth no está configurado.

src/features/dashboard/components/settings/ — cuenta y sesiones

FileChange this when you want to…
actions.tsPassword change, session list/revoke server actions
config.tsPassword length limits, name length limits
components/security-settings-page.tsxSecurity UI (password form, session list)
components/profile-settings-page.tsxProfile name and avatar

Ruta: src/app/dashboard/settings/account/security/page.tsx carga las sesiones en el servidor y renderiza SecuritySettingsPage.

Protección de rutas

FileChange this when you want to…
src/proxy.tsEdge redirects for /dashboard (session + verification gate)
src/app/dashboard/layout.tsxDashboard shell gate and user bootstrap

Email transaccional (relacionado con auth)

FileChange this when you want to…
src/lib/email/index.tsVerification, reset, welcome send functions
src/lib/email/templates/verification-email.tsxVerification email content
src/lib/email/templates/password-reset-email.tsxReset email content
src/lib/email/templates/welcome-email.tsxWelcome email content
src/lib/email/templates/shared.tsxEmail brand name and layout

Variables de entorno para auth: ver Variables de entorno.


Siguientes pasos

Configuración OAuth — Configuración paso a paso de Google y GitHub.

Variables de entorno — Referencia completa de env, incluyendo BETTER_AUTH_* y claves OAuth.