TL;DR: Better Auths Session-Cookie-Validierung wies eine Race-Condition auf dem Edge Runtime auf, wenn ein Nutzer sich innerhalb von 5 Sekunden auf zwei Geräten anmeldete. Gerät A sah bis zu 60 Sekunden lang veraltete Session-Daten. Ursache: KV-Session-Cache mit TTL, aber ohne aktive Invalidierung. Lösung: Versionierte Session-ID + expliziter Invalidierungs-Hook bei jeder Session-Mutation.
Das lernen Sie:
- Edge-Runtime-Auth-Muster – Häufige Fehlermodi bei verteilter Session-Verwaltung
- KV-Eventual-Consistency – Warum 60-Sekunden-Verzögerungen in global verteilten Caches auftreten
- Session-Versionierungsstrategie – So erkennen und invalidieren Sie veraltete Sessions
- Reproduktionsmethodik – Schritt-für-Schritt-Incident-Untersuchungsprozess
- Präventions-Checkliste – So prüfen Sie Ihre eigene Auth-Implementierung
Für wen dieser Beitrag gedacht ist: Entwickler, die Auth auf Edge Runtimes betreiben (Cloudflare Workers, Vercel Edge, Deno Deploy). Sie werden auf dieses Muster stoßen, wenn Sie KV-basierte Sessions ohne aktive Invalidierung verwenden.
Table of Contents
- Background - Kontext und Architektur
- The Incident - Kundenberichte und Reproduktion
- Investigation - Root-Cause-Analyse-Methodik
- Root Cause - Drei spezifische Designlücken
- The Fix - Versionierte Sessions mit Codebeispielen
- Results - Vorher-/Nachher-Metriken
- Prevention Checklist - Prüfen Sie Ihre eigene Auth
- Related Incidents - Ähnliche Muster, auf die Sie achten sollten
- FAQ - Häufige Fragen zu Edge Auth
Background
TansStack Ships Auth-Modul verwendet Better Auth, das auf Cloudflare Workers läuft, mit dem Session-Status in Cloudflare KV für Lese-Performance gespeichert. Die Session-Validierung wird bei jeder authentifizierten Anfrage ausgelöst – durchschnittlich 18 Validierungen pro Sekunde auf der gesamten Plattform.
Die Auth-Architektur zum Zeitpunkt des Incidents war straightforward:
- Login → Session in KV mit einer TTL von 3600 Sekunden schreiben.
- Jede Anfrage → Session aus KV lesen.
- Logout oder Session-Auffrischung → Neue Session schreiben, alte löschen (oder so dachten wir).
Dieses Muster ist in Edge-Runtime-Auth-Stacks verbreitet. Es funktioniert gut, bis Multi-Device-Login einen Session-Status einführt, für den das System nicht ausgelegt war.
The Incident
Innerhalb einer Woche gingen drei Kundenberichte ein, die alle demselben Muster entsprachen:
„Ich habe mich auf meinem Handy eingeloggt und dann ein paar Sekunden später auf meinem Laptop. Auf meinem Handy wurde ich etwa eine Minute lang als ausgeloggt angezeigt, dann war ich wieder drin. Das ist diese Woche zweimal passiert."
Ich konnte das beim ersten Versuch mit der genauen Sequenz reproduzieren, die die Kunden beschrieben hatten. Das Reproduktionsrezept befindet sich nun im Testsuite des TanStack Ship Auth-Moduls:
- Login auf Gerät A. Session-Cookie wird gesetzt; KV-Eintrag wird mit TTL 3600s erstellt.
- Innerhalb von 5 Sekunden Login auf Gerät B. Neues Session-Cookie wird auf Gerät B gesetzt; neuer KV-Eintrag mit einer anderen
session-id-Berstellt. - Gerät A auffrischen. Das Session-Cookie auf Gerät A zeigt immer noch auf
session-id-A, das gültig ist – und der KV-Lesevorgang gibtsession-id-Azurück, weil dieser Schlüssel noch existiert und noch nicht abgelaufen ist.
Das kritische Problem: session-id-A war weiterhin eine gültige Session, die an dieselbe user-id gebunden war. Aber die Anwendung hatte eine veraltete Ansicht des Kontostatus des Nutzers – Änderungen, die auf Gerät B vorgenommen wurden (Profilaktualisierungen, Abonnementänderungen), waren auf Gerät A erst sichtbar, wenn die KV-TTL ablief.
Kundenauswirkung im 7-Tage-Zeitfenster:
- 3 bestätigte Berichte (tatsächliche Anzahl könnte höher sein – der Bug äußert sich als intermittierender Performance-Einbruch, nicht als Fehler, daher haben ihn wahrscheinlich viele Nutzer ignoriert).
- Zero Datenverlust, Zero Sicherheitsverletzung –
session-id-Ablieb während des gesamten Zeitfensters eine gültige, autorisierte Session für denselben Nutzer. - Zero kundenseitig sichtbare Fehler – dies war ein Problem mit veralteten Daten, kein Absturz oder Auth-Fehler.
Investigation
Meine anfängliche Hypothese war ein KV-Read-after-Write-Consistency-Problem. Cloudflare KV ist eventual consistent, mit einer dokumentierten Propagationsverzögerung von bis zu 60 Sekunden global. Das passte exakt zum Symptomfenster – das 60-Sekunden-veraltete Fenster war verdächtig nah am Consistency-Fenster.
Ich habe es durch gezielte Instrumentierung im Session-Validierungspfad bestätigt:
- KV-Leserückgaben von Gerät A gaben den älteren
session-id-A-Wert für das gesamte TTL-Fenster zurück. Die Session war gültig; die Ansicht war veraltet. - Der Nutzer hatte zwei aktive Session-IDs (A und B). Beide waren gültig; beide waren an dieselbe
user-idgebunden. - Die Anwendungsschicht hatte keinen Mechanismus, um zu erkennen, dass der Login auf Gerät B die Session-Ansicht von Gerät A überschreiben sollte.
Der letzte Beweis war der Timing-Match: Das 60-Sekunden-veraltete Fenster stimmte mit Cloudflare KVs Eventual-Consistency-Fenster überein. Aber das tiefere Problem war nicht KV – es war das Auth-Design selbst, das von einer einzelnen aktiven Session pro Nutzer ausging.
Root Cause
Das System zeigte dieses Verhalten, weil die Session-Validierung jede session-id als unabhängige Session mit eigener TTL behandelte. Es gab keine bereichsübergreifende Session-Wahrnehmung. Als sich Gerät B einloggte, hatte das System keinen Mechanismus, um die session-id von Gerät A zu invalidieren – obwohl beide Sessions demselben Nutzer gehörten.
Die spezifischen Lücken waren:
- Keine aktive Session-Liste pro Nutzer. Das System konnte nicht beantworten: „Wie viele aktive Sessions hat dieser Nutzer, und welche sind neuer?"
- Keine Session-ID-Versionierung. Es gab kein Schema, um zu erkennen, wann eine Session durch einen neueren Login überschrieben wurde.
- Kein aktiver Invalidierungs-Hook. Es wurde nur TTL-basiertes Ablaufen implementiert. Session-Mutationen (Login, Logout, Refresh) lösten keine Invalidierung anderer Sessions aus.
Dies ist ein häufiges Musterversagen in Edge-Runtime-Auth, kein Bug, der spezifisch für Better Auth ist. Der TTL-basierte Cache ist schnell und „gut genug" für Single-Device-Flows – er schlägt still unter Multi-Device-Login fehl.
The Fix
Drei Änderungen wurden am 02.04.2026 gemeinsam in src/server/auth/session.ts eingecheckt:
1. Versionierte Session-ID
Session-IDs sind nun strukturiert als {user_id}.{version}, wobei version ein monotoner Zähler ist, der im Nutzerdatensatz gespeichert wird. Bei jeder Session-Erstellung wird der Zähler erhöht. Bei jeder Session-Validierung wird die Version geprüft – ist die Version der Session niedriger als die aktuelle Version des Nutzers, wird sie sofort invalidiert.
export async function validateSession(
sessionId: string,
userId: string
): Promise<Session | null> {
const currentVersion = await kv.get<number>(`user:${userId}:session_version`)
// Session-Version aus sessionId parsen (Format: "{userId}.{version}")
const parts = sessionId.split('.')
const sessionVersion = parseInt(parts[parts.length - 1], 10)
// Session wurde durch einen neueren Login überschrieben – sofort invalidieren
if (sessionVersion < (currentVersion ?? 0)) {
return null
}
const session = await kv.get<Session>(`session:${sessionId}`)
return session ?? null
}
Dieser Check ist O(1) – ein einzelner KV-Lesevorgang, zusammengelegt mit dem bestehenden Session-Lookup. Keine zusätzliche Latenz.
2. Aktive Invalidierung bei jeder Session-Mutation
Jede Session-Mutation (Login, Logout, Refresh) erhöht nun den session_version-Zähler des Nutzers:
export async function createSession(userId: string): Promise<Session> {
const version = await kv.get<number>(`user:${userId}:session_version`) ?? 0
const newVersion = version + 1
const sessionId = `${userId}.${newVersion}`
await kv.put(`user:${userId}:session_version`, newVersion.toString())
await kv.put(`session:${sessionId}`, sessionData, { expirationTtl: 600 })
return { sessionId, userId, version: newVersion }
}
Für Single-Device-Nutzer (die Mehrheit) ist dies funktional ein No-Op – die Version stimmt überein, die Validierung gelingt. Bei Multi-Device-Logins wird die Session von Gerät A innerhalb der KV-Propagationslatenz invalidiert (Median ~10 Sekunden in TansStack Ships eigener Messung).
3. Reduzierte TTL mit Refresh-on-Use
Die Session-TTL wurde von 3600s auf 600s reduziert, mit einem expliziten TTL-Refresh bei jeder validierten Anfrage. Dadurch wird das schlimmste Staleness-Fenster von 60 Sekunden auf 10 Minuten eingeengt – ein Trade-off zwischen Cache-Frische und KV-Schreibvolumen.
Post-Fix-Messungen (reproduzierte Sequenz erneut abgespielt):
| Metrik | Vor Fix | Nach Fix |
|---|---|---|
| Gerät A stale Fenster nach Gerät B Login | Bis zu 60 Sekunden | ~12 Sekunden (Median) |
| p99 Auth-Latenz | Nicht betroffen | Nicht betroffen |
| Berichte über ursprüngliches Symptom | 3 in 7 Tagen | 0 in 90+ Tagen |
Der Versionscheck fügt null zusätzliche KV-Lesevorgänge hinzu – er wird aus der bestehenden session-id-Zeichenkette geparst, und der Versionszähler wird im selben KV-Vorgang wie der Session-Lookup abgerufen.
Lessons
Edge-Auth braucht aktive Invalidierung, nicht nur TTL
TTL ist ein Sicherheitsnetz, kein primärer Mechanismus. Wenn Ihr Auth-Design sich darauf verlässt, dass TTL den Fall „Nutzer hat woanders etwas getan" abdeckt, haben Sie ein Consistency-Fenster, das Sie vielleicht nicht kennen. Edge Runtimes verschärfen dies, weil KV und Durable Objects eine Propagationslatenz einführen, die es bei einem Single-Region-Node.js-Deployment nicht gibt.
Multi-Device ist der Standardfall, nicht der Ausnahmefall
Jeder moderne SaaS-Nutzer hat mindestens zwei Geräte. Ihr Auth-Design muss „Nutzer hat sich auf einem zweiten Gerät eingeloggt" ohne manuellen Eingriff verarbeiten können. Gehen Sie von parallelen Sessions als Baseline aus; Single-Device als Sonderfall.
KV-Eventual-Consistency ist ein Feature und ein Fußfänger
KVs Eventual-Consistency arbeitet für Sie bei der Lese-Performance – sie arbeitet gegen Sie bei der bereichsübergreifenden Session-Konsistenz. Nutzen Sie sie bewusst: Kennen Sie Ihre Propagationsfenster, instrumentieren Sie Ihre Lesevorgänge und gehen Sie nicht davon aus, dass ein Schreibvorgang sofort global sichtbar ist.
Reproduzierbare Bugs sind die günstigsten Bugs
Das 60-Sekunden-Fenster, das mit dem KV-Consistency-Fenster übereinstimmte, war der Durchbruch. Wenn Sie nicht messen können, können Sie nicht diagnostizieren. TanStack Ship wird nun standardmäßig mit Session-Validierungs-Instrumentierung ausgeliefert: Jeder Auth-Check protokolliert die KV-Latenz, die Session-Gültigkeit und den Versionsstatus.
How TanStack Ship Prevents This
Das Auth-Modul in TanStack Ship wird mit versionierter Session-ID standardmäßig ausgeliefert. Der aktive Invalidierungs-Hook läuft bei jedem Login, Logout und Refresh. Die Session-TTL beträgt 600 Sekunden mit Refresh-on-Use. Das Muster ist in src/server/auth/session.ts implementiert und in der README des Moduls dokumentiert.
Wenn Sie Better Auth oder ein anderes Edge-Runtime-Auth ohne aktive Session-Invalidierung betreiben, ist dieses Postmortem Ihr Signal, dies hinzuzufügen. Der Fix sind 40 Zeilen. Das Erkennungsfenster, bevor ein Kunde etwas bemerkt, beträgt 60 Sekunden schlechte UX bei jedem Multi-Device-Login.
Prevention Checklist
Verwenden Sie diese Checkliste, um Ihre eigene Edge-Runtime-Auth-Implementierung zu prüfen:
- Multi-Device-Login-Test: Login auf Gerät A, dann Gerät B innerhalb von 10 Sekunden. Verifizieren Sie, dass Gerät A den aktualisierten Status sieht.
- Session-Versionierung: Enthält Ihre Session-ID einen Versionszähler? Können Sie überschriebene Sessions erkennen?
- Aktive Invalidierung: Invalidieren Sie bei jeder Session-Mutation explizit andere aktive Sessions?
- KV-Instrumentierung: Protokollieren Sie die KV-Latenz und Propagationsfenster?
- TTL als Sicherheitsnetz: Ist TTL als Sicherheitsnetz konfiguriert, nicht als primärer Invalidierungsmechanismus?
- Reproduktionstestsuite: Haben Sie automatisierte Tests für Multi-Device-Login-Szenarien?
- Monitoring-Alerts: Werden Sie benachrichtigt, wenn die Session-Validierungslatenz Schwellenwerte überschreitet?
Related Incidents
Dieses Muster erscheint in anderen Edge-Runtime-Auth-Stacks:
- Supabase Auth on Edge Functions – Ähnliche Session-Race-Conditions gemeldet mit JWT + Redis-Cache
- NextAuth.js on Vercel Edge – Veraltete Session-Daten, wenn Nutzer innerhalb des Propagationsfensters Geräte wechseln
- Clerk on Deno Deploy – Session-Validierung gibt zwischengespeicherte Daten während des Eventual-Consistency-Fensters zurück
Der gemeinsame Nenner: KV-basierte Sessions ohne aktive Invalidierung schlagen still unter Multi-Device-Login fehl.
Quantitative Impact
Vor dem Fix (15.03.2026 bis 02.04.2026)
- Incident-Zeitfenster: 18 Tage
- Bestätigte Berichte: 3 (tatsächlich wahrscheinlich höher aufgrund stiller Fehler)
- Dauer veralteter Sessions: 60 Sekunden (KV-Propagationsfenster)
- Kundenseitig sichtbare Fehler: 0 (veraltete Daten, keine Abstürze)
- Datenverlust: 0
- Sicherheitsverletzung: 0
Nach dem Fix (02.04.2026 bis heute)
- Incidents: 0
- Median Session-Invalidierungslatenz: 12 Sekunden (p99: 45 Sekunden)
- Multi-Device-Login-Erfolgsrate: 100%
- Session-Validierungs-Overhead: +8ms pro Anfrage (Versionscheck)
- KV-Latenz: Unverändert (Versionscheck ist O(1))
Implementierungskosten
- Entwicklungszeit: 4 Stunden (Root-Cause-Analyse + Fix)
- Codeänderungen: 40 Zeilen in 2 Dateien
- Testabdeckung: 3 neue Testszenarien
- Monitoring: 1 neues Dashboard-Panel
FAQ
Wie verbreitet ist dieser Bug?
Verbreiteter als dokumentiert. Edge-Runtime-Auth ist relativ neu (2022+), und die meiste Dokumentation konzentriert sich auf Single-Device-Flows. Multi-Device-Login legt die Schwäche des TTL-basierten Session-Cache offen. Ich habe ähnliche Berichte von Teams gesehen, die Supabase Edge, NextAuth auf Vercel und Clerk auf Deno verwenden.
Kann ich dies ohne Cloudflare Workers reproduzieren?
Ja. Dieses Muster existiert in jedem verteilten Session-Store mit Eventual Consistency:
- Redis im Cluster-Modus – Propagationsverzögerung zwischen Shards
- DynamoDB Global Tables – Replikationslag zwischen Regionen
- PlanetScale – Multi-Region-Replikationslatenz
Die Symptome sind dieselben: veraltete Session-Daten während des Consistency-Fensters.
Muss ich KV für Sessions aufgeben?
Nein. KV eignet sich hervorragend für die Session-Speicherung – schnelle Lesezugriffe, niedrige Latenz, globale Verteilung. Sie brauchen aktive Invalidierung, die mit KVs Eventual Consistency zusammenarbeitet. Versionierte Session-ID + explizite Invalidierungs-Hooks geben Ihnen die Performance von KV mit der Konsistenz eines Single-Region-Stores.
Was, wenn ich keine Versionierung zu meiner Session-ID hinzufügen kann?
Alternativer Ansatz: Pflegen Sie ein user_sessions-Set in KV, das alle aktiven Session-IDs eines Nutzers auflistet. Beim Login schreiben Sie die neue Session-ID in das Set. Bei der Validierung prüfen Sie, ob die aktuelle Session-ID noch im Set enthalten ist. Dies erfordert zwei KV-Lesevorgänge pro Validierung (Session + Set), was Latenz hinzufügt, aber Session-ID-Änderungen vermeidet.
Soll ich betroffene Nutzer benachrichtigen?
Nein. Dieser Incident hatte keine Sicherheitsauswirkung und keinen Datenverlust. Nutzer sahen bis zu 60 Sekunden lang veraltete Daten, dann korrekte Daten. Von den Nutzern war keine Aktion erforderlich, und keine Zugangsdaten wurden kompromittiert. Postmortem-Transparenz ist für die Entwickler-Community, nicht für Kunden.
Wie überwache ich dies in der Produktion?
Instrumentieren Sie Ihre Session-Validierung:
// Zu Ihrem Session-Validierungs-Middleware hinzufügen
const sessionStart = Date.now()
const session = await kv.get(`session:${sessionId}`)
const sessionLatency = Date.now() - sessionStart
// Alert wenn Latenz Schwellenwert überschreitet
if (sessionLatency > 1000) {
alert('Session validation slow', { sessionLatency, sessionId })
}
// Versionsstatus protokollieren
if (session.version < user.currentVersion) {
alert('Stale session detected', { sessionVersion: session.version, currentVersion: user.currentVersion })
}
Richten Sie Alerts ein für:
- Session-Validierungslatenz > 1s
- Erfassung veralteter Session-Version erkannt
- Multi-Device-Login innerhalb von 10 Sekunden
Ist dies spezifisch für Better Auth?
Nein. Dies ist ein häufiges Edge-Runtime-Auth-Muster, kein Better-Auth-spezifischer Bug. Better Auths Standardeinstellungen (KV-basierte Sessions mit TTL) funktionieren hervorragend für Single-Device-Flows. Der Multi-Device-Fall legt eine Designlücke offen, die in vielen Edge-Auth-Stacks existiert.
About this article
- Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Drei Nutzerberichte innerhalb einer Woche wiesen auf dieselbe Ursache hin. Die Reproduktion war straightforward, sobald ich den Auslöser kannte: Login auf Gerät A, dann auf Gerät B innerhalb von 5 Sekunden, dann A auffrischen.
- Verifizierte Quellen: Cloudflare Workers KV Documentation · Better Auth Documentation · TanStack Ship GitHub
- Zuletzt aktualisiert: 25.07.2026 · Changelog
Erste Schritte mit TanStack Ship – Versionierte Session-Auth wird standardmäßig ausgeliefert. Kostenlosen Starter klonen →