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.
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
| Feature | Status | Notes |
|---|---|---|
| Email / password sign-up | Enabled | Verification required before dashboard access |
| Email / password sign-in | Enabled | Redirects unverified users to /verify-email |
| Google OAuth | Optional | Enabled when GOOGLE_* env vars are set |
| GitHub OAuth | Optional | Enabled when GITHUB_* env vars are set |
| Email verification | Required | Sent on sign-up; resend on sign-in if still unverified |
| Password reset | Enabled | Requires Resend (RESEND_API_KEY, EMAIL_FROM) |
| Change password | Enabled | Settings → Security; revokes other sessions |
| Sign out | Enabled | User menu in the dashboard header |
| Session management | Enabled | List and revoke sessions in Settings → Security |
| Account linking | Enabled | Google 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:
src/proxy.ts— puerta en el edge para/dashboardy/dashboard/*. Redirige usuarios no autenticados a/sign-iny no verificados a/verify-email.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.
| Step | What happens |
|---|---|
| Sign up | Better Auth sends a verification link via sendVerificationEmail |
| Click link | User is verified; they can sign in |
| Unverified sign-in | Redirect 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
| Route | Purpose |
|---|---|
/forgot-password | Request a reset link |
/reset-password?token=… | Set a new password from the email link |
Flujo:
- El usuario envía el email en
/forgot-password - El cliente llama a
authClient.requestPasswordResetconredirectToapuntando a/reset-password - Better Auth envía el email vía
sendResetPasswordenauth.ts - 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
| File | Change this when you want to… |
|---|---|
auth.ts | Enable/disable providers, toggle verification, customize email hooks, add Better Auth plugins, change account linking |
session.ts | Adjust how server components read the session (getCachedSession) |
client.ts | Configure the browser auth client (base URL is inferred automatically) |
social.ts | Change how Google/GitHub “configured” checks work |
safe-client-error.ts | Edit 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
| Path | Change 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.tsx | Shared 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
| File | Change this when you want to… |
|---|---|
actions.ts | Password change, session list/revoke server actions |
config.ts | Password length limits, name length limits |
components/security-settings-page.tsx | Security UI (password form, session list) |
components/profile-settings-page.tsx | Profile 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
| File | Change this when you want to… |
|---|---|
src/proxy.ts | Edge redirects for /dashboard (session + verification gate) |
src/app/dashboard/layout.tsx | Dashboard shell gate and user bootstrap |
Email transaccional (relacionado con auth)
| File | Change this when you want to… |
|---|---|
src/lib/email/index.ts | Verification, reset, welcome send functions |
src/lib/email/templates/verification-email.tsx | Verification email content |
src/lib/email/templates/password-reset-email.tsx | Reset email content |
src/lib/email/templates/welcome-email.tsx | Welcome email content |
src/lib/email/templates/shared.tsx | Email 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.