G.STANCUTA
Veröffentlicht · 2026 · 05 · 278 Min. Lesezeit

Better Auth und Resend: Authentifizierung, die ein Solo-Entwickler wirklich ausliefern kann

  • auth
  • email
  • better-auth
  • resend

Self-hosted Auth mit Better Auth, transaktionale E-Mails mit Resend. Kein Vendor Lock-in, keine versteckten Kosten, und ein Setup, das ein KI-Coding-Agent aus einer Markdown-Datei reproduzieren kann.

Authentifizierung ist der Teil jedes Projekts, der einfach wirkt, bis man drei Tage später um Mitternacht OAuth-Redirect-Loops debuggt. Meine Anforderung für NearYou war klar: E-Mail- und Passwort-Anmeldung, Google Social Login, E-Mail-Verifizierung, Passwort-Reset, Zwei-Faktor später, und null monatliche Kosten für einen Dienst, der in der frühen Entwicklung wochenlang inaktiv sein könnte. Better Auth plus Resend ist dieser Stack. Ich zeige dir genau, wie er zusammenpasst.

Warum Better Auth

Better Auth ist eine self-hosted Authentifizierungsbibliothek für das JavaScript-Ökosystem. Du installierst es als Paket, schließt es über einen Adapter an deine bestehende Datenbank an und besitzt die gesamte Session- und Benutzertabelle. Kein externer Authentifizierungsdienst ruft nach Hause. Kein Preis pro monatlich aktivem Nutzer, der dich überrascht, wenn ein Beitrag viral geht. Keine Anbietermigration, wenn sich die Preise ändern.

Der Funktionsumfang ist produktionsbereit von Anfang an: E-Mail und Passwort, Social Provider (Google, Facebook, GitHub und mehr), E-Mail-Verifizierung, Passwort-Reset, Zwei-Faktor-Authentifizierung über TOTP und ein Prisma-Adapter, der die notwendigen Schema-Modelle automatisch generiert. Sessions werden in deiner eigenen Datenbank gespeichert. Token-Rotation wird verwaltet. Die Client-Bibliothek liefert typisierte Hooks für React und andere Frameworks, sodass du keine eigene useSession-Logik schreiben musst.

Das Einzige, was Better Auth nicht enthält, ist die E-Mail-Zustellung. Es stellt Hooks bereit, du verbindest den Transport. Das ist die richtige Trennung: Auth-Logik bleibt in Better Auth, Zustellung geht an einen Dienst, der genau dafür gebaut ist.

Isometrisches Schema von Better Auth zwischen der App und der Datenbank, mit einem Pfeil zu Resend für ausgehende E-Mail-Zustellung
Better Auth besitzt Sessions und Nutzer. Resend besitzt die Zustellung. Die App besitzt keines von beiden direkt.

Warum Resend für transaktionale E-Mails

Resend ist ein entwicklerorientierter transaktionaler E-Mail-Dienst. Das kostenlose Tier bietet 3.000 E-Mails pro Monat und 100 pro Tag, was jedes Frühphasenprojekt komfortabel abdeckt. Die kostenpflichtigen Preise sind niedrig genug, dass man sich keine Gedanken machen muss, bis man eine echte Nutzerbasis hat. Die API ist ein einziger Funktionsaufruf. Keine SMTP-Konfiguration, kein Alptraum mit Authentifizierungs-Headern, nirgendwo XML.

Die Anforderungen sind minimal, aber nicht verhandelbar. Du brauchst eine Sendedomain, die du kontrollierst. Du musst drei DNS-Einträge zu dieser Domain hinzufügen: einen SPF-Eintrag, einen DKIM-Schlüssel, den Resend für dich generiert, und eine DMARC-Richtlinie. Du brauchst einen API-Schlüssel vom Resend-Dashboard. Und du brauchst eine klare, konsistente from-Adresse, die zu deiner verifizierten Domain passt. Sobald diese vorhanden sind, funktioniert die Zustellung und die Inbox-Platzierung ist solide.

Den Resend-Aufruf verdrahten

Das Resend Node SDK ist ein kleiner Wrapper um ihre REST API. Installiere es mit npm install resend, exportiere eine typisierte Funktion pro E-Mail-Typ und rufe sie aus deinen Better Auth Hooks auf. Die wichtigste Disziplin: Baue niemals HTML-Strings inline in der Auth-Konfiguration. Verlagere das in ein dediziertes lib/email.ts-Modul, damit es testbar und austauschbar ist.

ts
import { Resend } from 'resend';

const resend = new Resend(process.env.RESEND_API_KEY);

export async function sendVerificationEmail(to: string, url: string) {
  await resend.emails.send({
    from: 'NearYou <noreply@mail.nearyou.app>',
    to,
    subject: 'Verify your email address',
    html:
      '<p>Click the link below to verify your account:</p>' +
      '<p><a href="' + url + '">' + url + '</a></p>',
  });
}

Halte RESEND_API_KEY in deiner .env-Datei und committe sie niemals. Die from-Adresse muss exakt mit deiner verifizierten Domain übereinstimmen. Wenn du die Sendedomain später änderst, aktualisiere diesen String und verifiziere erneut im Resend-Dashboard. Die Funktion ist bewusst einfach: ein Send-Aufruf, eine Fehleroberfläche. Füge vor dem Produktionsgang ordentliche Fehlerbehandlung und Logging hinzu.

Better Auth damit verbinden

Die Better Auth Konfiguration lebt in einer einzigen auth.ts-Datei im Projektstamm oder in lib/. Der emailVerification-Block ist der Ort, an dem du deine Send-Funktion übergibst. Der Hook empfängt das User-Objekt und eine vorgefertigte Verifizierungs-URL. Du leitest beides an deinen Resend-Wrapper weiter. Die URL ist intern von Better Auth signiert und zeitlich begrenzt, sodass du selbst keine Tokens verwaltest.

ts
import { betterAuth } from 'better-auth';
import { prismaAdapter } from 'better-auth/adapters/prisma';
import { prisma } from './lib/prisma';
import { sendVerificationEmail } from './lib/email';

export const auth = betterAuth({
  database: prismaAdapter(prisma, { provider: 'mysql' }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
    },
  },
  emailVerification: {
    sendOnSignUp: true,
    autoSignInAfterVerification: true,
    sendVerificationEmail: async ({ user, url }) => {
      await sendVerificationEmail(user.email, url);
    },
  },
});

Das Flag requireEmailVerification: true blockiert die Anmeldung, bis die E-Mail bestätigt ist. autoSignInAfterVerification: true bedeutet, dass der Nutzer sofort nach dem Klick auf den Link in seinem Posteingang in der App landet, kein zweiter Anmeldeschritt. Diese Kombination gibt dir einen sauberen Onboarding-Flow mit minimalem Code.

  • Passwort-Reset: füge sendResetPassword zum emailAndPassword-Block hinzu, gleiches Muster wie der Verifizierungs-Hook.
  • Social Provider: setze google.clientId und google.clientSecret aus der Umgebung. Better Auth verwaltet die OAuth-Callback-Route automatisch.
  • Zwei-Faktor: füge import { twoFactor } from "better-auth/plugins" hinzu und nimm es in das plugins-Array auf. Better Auth liefert die TOTP-Logik.
  • Session-Ablauf: setze session.expiresIn und session.updateAge, um zu steuern, wie lange Tokens leben und wann sie sich automatisch aktualisieren.

DNS-Anforderungen: der Teil, der dich blockiert

E-Mail-Zustellbarkeit steht und fällt mit DNS. Resend sendet nicht von einer nicht verifizierten Domain. Selbst wenn du diese Prüfung irgendwie umgehst, landen E-Mails ohne SPF- und DKIM-Ausrichtung im Spam. Das ist der einzige Schritt mit einer echten Wartezeit: DNS-Änderungen können bis zu 48 Stunden benötigen, um sich global zu verbreiten, in der Praxis ist es mit modernen Registraren jedoch meist unter einer Stunde.

Die drei Einträge, die du auf deiner Sendedomain benötigst: SPF teilt empfangenden Servern mit, welche Hosts für deine Domain senden dürfen. DKIM hängt eine kryptografische Signatur an ausgehende Nachrichten an, damit Empfänger überprüfen können, dass sie nicht manipuliert wurden. DMARC teilt empfangenden Servern mit, was zu tun ist, wenn SPF- oder DKIM-Prüfungen fehlschlagen. Resend zeigt dir die genauen Werte, die du nach dem Hinzufügen der Domain in deinen DNS-Anbieter einfügen musst.

Schema eines KI-Agenten, der eine AGENTS.md-Datei mit Sendedomain, From-Adresse und DNS-Checkliste liest und dann E-Mail-Einstellungen korrekt konfiguriert
Die Markdown-Gedächtnisdatei ist die einzige Quelle der Wahrheit für die E-Mail-Konfiguration. Der Agent liest sie, nicht die Umgebungsvariablen, die er nicht sehen kann.

Konfiguration in einer Markdown-Gedächtnisdatei persistieren

Ich verwende Claude Code als KI-Coding-Agent bei NearYou. Der Agent schreibt Auth-Konfiguration, verdrahtet E-Mail-Hooks, aktualisiert Umgebungsdateien und debuggt Zustellungsprobleme. Damit das zuverlässig über Sitzungen hinweg funktioniert, benötigt der Agent persistentes Gedächtnis der genauen E-Mail-Einrichtung: welche Domain verifiziert ist, was die From-Adresse ist, welche DNS-Einträge vorhanden sind und wie die Umgebungsvariablennamen lauten.

Ohne eine Gedächtnisdatei muss der Agent bei jeder neuen Sitzung fragen, ableiten oder raten. Er könnte die falsche From-Adresse verwenden, auf eine nicht verifizierte Domain verweisen oder den Hook an eine Umgebungsvariable mit einem anderen Namen verdrahten, als das, was tatsächlich in .env steht. Das sind kleine Fehler, die echte Debugging-Zeit kosten.

Die Lösung ist ein kurzer, präziser Abschnitt im AGENTS.md des Projekts (oder eine dedizierte .claude/email.md, wenn das Projekt groß ist). Halte die Sendedomain, die From-Adresse, die DNS-Eintrags-Checkliste und die Hook-Verdrahtungsnotizen dort. Der Agent liest diese Datei beim Sitzungsstart und bedient die E-Mail-Einrichtung beim ersten Versuch korrekt, jedes Mal.

md
## Auth + Email (Better Auth + Resend)

Sending domain: mail.nearyou.app
From address:   noreply@mail.nearyou.app
Resend API key: env var RESEND_API_KEY

### DNS records required on mail.nearyou.app
- SPF:   TXT  "v=spf1 include:amazonses.com ~all"
- DKIM:  TXT  resend._domainkey  <value from Resend dashboard>
- DMARC: TXT  _dmarc  "v=DMARC1; p=quarantine; rua=mailto:dmarc@nearyou.app"

### Email hooks wired in auth.ts
- emailVerification.sendVerificationEmail  -> sendVerificationEmail()
- emailAndPassword.sendResetPassword       -> sendPasswordResetEmail()

### Gotchas
- Resend requires the from domain to be verified before any email sends.
- DNS propagation can take up to 48h; verify in the Resend dashboard.
- Always set autoSignInAfterVerification: true so the UX is not broken post-verify.
- Never hardcode the from address; keep it in this file so the agent reads it.

Diese Datei ist der Unterschied zwischen einem Agenten, der deinen E-Mail-Stack sicher konfiguriert, und einem, der dir drei Fragen stellt, bevor er eine einzige Zeile schreibt. Es ist keine Dokumentation für Menschen. Es ist ein kompaktes Kontextdokument für ein System, das dein Resend-Dashboard, deine DNS-Einträge oder deine .env-Datei nicht sehen kann. Jede Zeile darin verdient ihren Platz, indem sie einen echten Fehler verhindert.

Der vollständige Stack in Produktion

Bei NearYou sind Better Auth und Resend seit den ersten Beta-Nutzern in Produktion. Der Auth-Flow: Registrierung mit E-Mail und Passwort oder Google, Erhalt einer Verifizierungs-E-Mail, die innerhalb weniger Sekunden über Resend gesendet wird, Klick auf den Link, Landen in der App. Der Passwort-Reset verwendet denselben Resend-Wrapper. Zwei-Faktor über TOTP ist verdrahtet, aber für Nutzer optional. Die gesamte Auth-Oberfläche ist self-hosted, keine Anbieterabhängigkeit außer Resend für die Zustellung.

Der Betriebskostenanteil ist vernachlässigbar. Das Resend Free Tier verwaltet die aktuelle Nutzerbasis mit Spielraum. Wenn es über das kostenlose Limit wächst, sind die Kosten pro E-Mail niedrig genug, um eine Rundungsfehler im Infrastrukturbudget zu bleiben. Better Auth hat überhaupt keine Kosten pro Nutzer. Vergleiche das mit Auth0- oder Clerk-Preisen im großen Maßstab, und die Rechnung liegt nicht einmal nah.

Das beste Auth-Setup ist das, das du besitzt, verstehst und um 2 Uhr nachts debuggen kannst, ohne ein Anbieter-Support-Ticket zu öffnen.

Wenn du ein neues JavaScript- oder TypeScript-Projekt baust und Authentifizierung brauchst, fange hier an. Installiere Better Auth, schließe es an deine bestehende Prisma-Datenbank an, füge den Resend-Wrapper hinzu, setze die DNS-Einträge und fülle dein AGENTS.md aus. Du wirst in einem halben Tag ein funktionierendes, produktionsreifes Auth-System haben und das nächste Jahr keinen Gedanken daran verschwenden.

Portfolio · Schriftfeld
Gezeichnet von
G. STANCUTA
Disziplin
AI & AUTOMATION
Standort
MORTER · SÜDTIROL
Status
Verfügbar
Sprachen
IT · EN · RO · DE+
Stack
PLOI · HETZNER
Revision
REV 2026.A
2026

© 2026 Gabriel Stancuta · jumpinotech.com — Mit KI entworfen, gebaut, um sich selbst zu betreiben.