Dokumentation

Better Auth

Wie Motoko Base Authentifizierung mit Better Auth handhabt — E-Mail/Passwort, OAuth, Sessions, geschützte Routen, Verifizierung und Kontoverwaltung.

Öffnen inChatGPT (öffnet in neuem Tab)Claude (öffnet in neuem Tab)Cursor (öffnet in neuem Tab)Wie Motoko Base Authentifizierung mit Better Auth handhabt — E-Mail/Passwort, OAuth, Sessions, geschützte Routen, Verifizierung und Kontoverwaltung.

Motoko Base verwendet Better Auth für Authentifizierung. Sessions werden in PostgreSQL über den Drizzle-Adapter gespeichert. Es gibt keinen separaten Auth-Service — Postgres plus Env-Vars reichen für die lokale Entwicklung.

Auth-API-Routen sind unter /api/auth/* gemountet. Das Dashboard erfordert eine verifizierte Session vor dem Rendern.

Was out of the box mitgeliefert wird

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

Social-Sign-in-Buttons bleiben deaktiviert, bis OAuth-Credentials konfiguriert sind. Siehe OAuth-Setup für die schrittweise Provider-Einrichtung.

E-Mail und Passwort

Sign up (/sign-up) erfasst Name, E-Mail und Passwort. Better Auth erstellt den User und sendet eine Verifizierungs-E-Mail, wenn Resend konfiguriert ist.

Weil requireEmailVerification aktiv ist, meldet die Registrierung den User nicht automatisch an. Nach der Registrierung sehen sie einen „Check your email“-Screen und müssen vor dem Zugriff auf /dashboard verifizieren.

Sign in (/sign-in) akzeptiert E-Mail und Passwort. Bei Erfolg leitet der Client nach /dashboard um. Ist die E-Mail nicht verifiziert, gibt Better Auth 403 EMAIL_NOT_VERIFIED zurück und das Formular leitet nach /verify-email um.

Passwortregeln für Registrierung und Passwortänderung werden in src/features/dashboard/schemas/security.ts validiert (MIN_PASSWORD_LENGTH = 8 standardmäßig).

Google- und GitHub-OAuth

Beide Provider sind in src/lib/auth/auth.ts verdrahtet und werden nur aktiviert, wenn Env-Vars vorhanden sind. Der Client nutzt authClient.signIn.social({ provider: "google" | "github" }) aus den Sign-in- und Sign-up-Formularen.

OAuth-User werden typischerweise vom Provider als verifiziert markiert. Account Linking ist für Google und GitHub aktiviert, damit ein zurückkehrender Social-User an ein bestehendes E-Mail-Konto angehängt werden kann, wenn Better Auth dem Provider vertraut.

Vollständiges Provider-Setup: OAuth-Setup.

Sessions

Sessions werden in der Tabelle session gespeichert (src/lib/db/schema/auth.ts). Jede Session hat Token, Ablauf, IP und User-Agent.

Server-seitige Reads nutzen getCachedSession() aus src/lib/auth/session.ts. Es wrappt auth.api.getSession() in React cache(), damit Layout, Seiten und Server Actions derselben Anfrage eine Lookup teilen.

Client-seitige Calls nutzen authClient aus src/lib/auth/client.ts (Better Auth React Client).

Beispiel — Session in einer Server Component oder Action prüfen:

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

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

Geschützte Routen

Dashboard-Routen unter /dashboard sind in zwei Schichten geschützt:

  1. src/proxy.ts — Edge-Gate für /dashboard und /dashboard/*. Leitet nicht authentifizierte User nach /sign-in und nicht verifizierte nach /verify-email um.
  2. src/app/dashboard/layout.tsx — Server-Layout, das dieselben Checks vor dem Rendern der Shell wiederholt.

Einzelne Seiten und Server Actions rufen ebenfalls getCachedSession() auf und leiten um oder geben Fehler zurück, wenn nötig. Dieses Defense-in-Depth-Muster hält API-Routen und Actions sicher, auch wenn eine Seite den Check vergisst.

Um eine neue Route zu schützen, legen Sie sie unter src/app/dashboard/ ab (erbt Layout + Proxy) oder rufen Sie getCachedSession() auf und leiten manuell um.

E-Mail-Verifizierung

Verifizierung ist für den Dashboard-Zugang erforderlich.

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

E-Mail-Zustellung erfordert RESEND_API_KEY und EMAIL_FROM. Ohne Resend startet die App, aber Verifizierungs-E-Mails werden nicht gesendet — konfigurieren Sie E-Mail, bevor Sie die Registrierung lokal testen.

Der Inhalt der Verifizierungs-E-Mail liegt in src/lib/email/templates/verification-email.tsx. Der Send-Hook ist in src/lib/auth/auth.ts unter emailVerification.sendVerificationEmail.

Passwort-Reset

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

Ablauf:

  1. User sendet E-Mail auf /forgot-password
  2. Client ruft authClient.requestPasswordReset mit redirectTo auf /reset-password auf
  3. Better Auth sendet die E-Mail über sendResetPassword in auth.ts
  4. User öffnet den Link und sendet ein neues Passwort über authClient.resetPassword

Reset-E-Mails erfordern Resend. Die Forgot-Password-Seite prüft die E-Mail-Konfiguration vor dem Senden.

Passwort ändern

Angemeldete User ändern ihr Passwort unter Settings → Security (/dashboard/settings/account/security).

Die UI ruft updatePasswordAction in src/features/dashboard/actions/security.ts auf, die auth.api.changePassword mit revokeOtherSessions: true nutzt — alle anderen Geräte werden nach erfolgreicher Änderung abgemeldet.

Passwortlängen-Limits kommen aus src/features/dashboard/schemas/security.ts.

Abmelden

Abmelden wird über das Dashboard-User-Menü ausgelöst. src/features/dashboard/components/dashboard-shell.tsx ruft auf:

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

Analytics- und Sentry-User-Kontext werden beim Abmelden im selben Handler geleert.

Konto- und Session-Verwaltung

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

Security (Passwort, Sessions) — Settings → Security:

  • Passwort ändern
  • Aktive Sessions auflisten (Browser, OS, letzte Aktivität)
  • Einzelne Sessions widerrufen
  • Alle anderen Sessions abmelden

Server-Logik liegt in src/features/dashboard/actions/security.ts (updatePasswordAction, revokeSessionAction (sessions load via src/features/dashboard/lib/security-settings.ts)).

Bei der Registrierung wird eine Willkommens-E-Mail aus dem Hook databaseHooks.user.create.after in auth.ts gesendet. Wenn Polar Billing konfiguriert ist, erstellt das Polar-Better-Auth-Plugin bei der Registrierung einen Billing-Kunden (src/lib/billing/providers/polar/auth-plugin.ts).


Wo ändere ich das?

Motoko Base teilt Auth auf in Server-Infrastruktur (src/lib/auth/), Auth-Seiten (src/app/…) und Kontoeinstellungen (src/features/dashboard/components/settings/). Es gibt keinen separaten Ordner src/features/auth/ — Auth-UI lebt in App-Routen; Kontoverwaltung lebt in Settings.

src/lib/auth/ — Server-Auth-Kern

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

Der Catch-all-API-Handler ist src/app/api/auth/[...all]/route.ts — Sie müssen ihn selten bearbeiten.

Datenbanktabellen: src/lib/db/schema/auth.ts (user, session, account, verification).

Auth-Seiten — Sign-in, Sign-up, Wiederherstellung

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)

Sign-in- und Sign-up-Seiten übergeben googleEnabled / githubEnabled von isGoogleAuthConfigured() und isGitHubAuthConfigured(), damit Buttons automatisch deaktiviert werden, wenn OAuth nicht konfiguriert ist.

src/features/dashboard/components/settings/ — Konto und Sessions

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

Route: src/app/dashboard/settings/account/security/page.tsx lädt Sessions serverseitig und rendert SecuritySettingsPage.

Routenschutz

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

Transaktions-E-Mail (auth-bezogen)

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

Env-Vars für Auth: siehe Umgebungsvariablen.


Nächste Schritte

OAuth-Setup — Schrittweise Google- und GitHub-Konfiguration.

Umgebungsvariablen — Vollständige Env-Referenz inklusive BETTER_AUTH_* und OAuth-Keys.