Wie teilt man Auth und Zahlungen zwischen Next.js, Expo und Tauri?
Entscheidend ist, ein Identitätsmodell und einen Entitlement-Speicher zu behalten. Web nutzt HttpOnly-Cookie-Sessions; Expo speichert nach dem Deep-Link-OAuth-Callback ein Bearer-Token in expo-secure-store; Tauri verwendet die Web-Session in seiner Webview wieder – alle werden von derselben Better-Auth-Instanz validiert. Zahlungen folgen derselben Regel: 8 Web-Gateways und RevenueCat Mobile IAP münden in ein idempotentes Webhook-Ledger, das Workspace-weite Entitlements schreibt, die jede Oberfläche liest.
Die zwei Nähte, an denen Cross-Platform-SaaS reißt
Fragen Sie ein Team, das eine Mobile-App an ein Web-SaaS angeschweißt hat, wo es wirklich wehtut – die Antwort ist nie UI. Es sind Identität und Geld: Der OAuth-Flow, der im Browser sauber zurückspringt, muss per Deep Link in die App zurückkehren; und der Kunde, der auf der Webseite gezahlt hat, erwartet sein Entitlement sofort auf dem Telefon.
Teams merken das meist erst, nachdem sie zwei halbe Lösungen ausgeliefert haben: Cookie-Logik, die in WKWebView still versagt, und ein RevenueCat-Entitlement, das mit der Stripe-Subscription in der Web-Datenbank kämpft. Die Reparatur ist architektonisch – und es ist zweimal dieselbe: ein Identitätsmodell, ein Entitlement-Speicher.
Eine Better-Auth-Instanz, drei Session-Transporte
supastack hält eine einzige Better-Auth-Konfiguration in @supastack/auth mit Oberflächen-spezifischen Einstiegspunkten. Beide Web-Apps (Next.js 16 und TanStack Start) nutzen HttpOnly-SameSite=Lax-Cookie-Sessions – CSRF-sicher per Default und kompatibel mit Server Components. Die Expo-App tauscht am Ende des Deep-Link-Callbacks den OAuth- oder Magic-Link-Abschluss gegen ein Bearer-Token, persistiert es im expo-secure-store (iOS Keychain / Android Keystore) und sendet es als Authorization-Header, validiert von derselben Auth-Middleware.
Tauris Desktop-Shell ist eine einzelne Webview auf die Web-App und erbt damit die Web-Session direkt – kein dritter Auth-Flow zu pflegen. Der Mobile-Auth-Guide und der Deep-Link-Guide dokumentieren den Callback-Vertrag; unser Web-+-Mobile-Monorepo-Guide zeigt den geteilten Client-Code.
// packages/auth/src/client.ts — one client, two storages
import { createAuthClient } from "better-auth/react";
import { expoClient } from "@better-auth/expo/client";
export function createCrossPlatformAuthClient(baseURL: string, storage?: any) {
return createAuthClient({
baseURL,
plugins: storage ? [expoClient({ scheme: "myapp", storage })] : [],
});
}
// Web: cookie session. Mobile: bearer token in SecureStore.
// Desktop: the web app's own session inside the Tauri webview.Acht Zahlungsgateways, ein Vertrag
Jeder Web-Zahlungsanbieter – Stripe, Lemon Squeezy, Polar, Creem, Dodo, Paddle, Whop und PayPal – steckt in demselben @supastack/billing-Vertrag, und jeder signierte Webhook landet erst in einem idempotenten webhook_event-Ledger, bevor er Entitlements anfassen darf. Provider-Retries und Out-of-Order-Delivery werden an der Datenbankgrenze zu harmlosen No-Ops statt zu Support-Tickets.
Mobile In-App-Käufe speisen sich über RevenueCat in dasselbe Ledger: Store-Receipts werden serverseitig verifiziert und Entitlements auf den Workspace geschrieben, nicht aufs Gerät – wer auf iOS gezahlt hat, ist auf Web und Desktop sofort ebenfalls bezahlt. Der RevenueCat-Guide erklärt die App-Store-/Play-Verdrahtung; idempotente Billing-Webhooks erklärt, warum das Ledger das tragende Teil ist.
Das Entitlement-Modell, das Synchronisation langweilig macht
Warum das langweilig bleibt: Entitlements leben auf dem Workspace und werden serverseitig aufgelöst. Kein Client hält »bezahlt« vor – das Web fragt die Session, Mobile fragt die API, Desktop fragt die Web-App – und alle drei bekommen dieselbe Antwort, weil es nur einen Datensatz gibt, der antworten kann.
Kauf wiederherstellen auf einem neuen Telefon, Stripe-Renewal im Web, ein Agency-Seat im Dashboard – alles Schreibzugriffe auf dieselben Entitlement-Zeilen, die jede Oberfläche bei der nächsten Anfrage liest. Es gibt keine Sync-Engine zu bauen, weil es nichts zu synchronisieren gibt.
| Oberfläche | Session-Transport | Zahlungspfad | Entitlements gelesen aus |
|---|---|---|---|
| Next.js 16 Web | HttpOnly-Cookie | Beliebiges der 8 Gateways → Webhook-Ledger | Gemeinsame Postgres-Entitlement-Zeilen |
| TanStack Start Web | HttpOnly-Cookie | Dieselben Adapter, dasselbe Ledger | Gemeinsame Postgres-Entitlement-Zeilen |
| Expo iOS / Android | Bearer-Token im expo-secure-store | RevenueCat IAP → serververifiziertes Receipt | Dieselben Zeilen (via typisierter API) |
| Tauri 2 Desktop | Web-Session in der Webview | Web-Checkout innerhalb der Shell | Dieselben Zeilen (via Web-App) |
| MV3-Extension | Workspace-API-Key | — (liest Workspace-Daten) | Dieselben Zeilen (via /api/v1) |
Was Sie nicht mehr bauen müssen
In Abendstunden umgerechnet ist das der Unterschied zwischen Fundament und Feature-Liste: der Deep-Link-Auth-Return, SecureStore-Token-Persistenz, acht replay-sichere Webhook-Integrationen, App-Store-Receipt-Verifizierung und ein Entitlement-Modell, das sich geräteübergreifend nie widerspricht. Alles ausgeliefert, getestet (693+ Tests laufen ohne Credentials) und dokumentiert.
Das $299 Full Bundle enthält alle Oberflächen in einem Repo – Seat-Zahlen und Agency-Stufen auf der Pricing-Seite.
FAQ: Auth & Zahlungen cross-plattform teilen
Fragen, die Teams stellen, bevor sie sich auf den einheitlichen Stack festlegen:
- Loggen sich Mobile-Nutzer separat vom Web ein?, Nein. Der OAuth- oder Magic-Link-Flow kehrt per Deep Link in die App zurück und stellt dieselbe Session aus; dieselbe Better-Auth-Instanz stellt aus, also stimmen Web und Mobile darin überein, wer Sie sind.
- Was passiert wenn jemand auf iOS zahlt aber die Web-App nutzt?, RevenueCat liefert den Kauf serverseitig; das Entitlement landet in denselben Workspace-Zeilen, die das Web liest – die Web-App zeigt beim nächsten Request »bezahlt«.
- Kann man nur mit Web starten und Apps später hinzufügen?, Ja – Auth und Billing leben in den Shared Packages, sodass Mobile- und Desktop-Apps sie erben, sobald diese Oberflächen aktiviert werden.
- Braucht die Tauri-App einen eigenen Checkout?, Nein – die Desktop-Shell nutzt Session und Checkout der Web-App in ihrer Webview wieder; es gibt keine zweite Zahlungsoberfläche abzusichern.