Next.js、Expo、Tauri間で認証と決済を共有するには?
1つのIDモデルと1つのエンタイトルメント保存先を保てるか次第です。WebはHttpOnly Cookieセッション、ExpoはディープリンクのOAuthコールバック後にBearerトークンをexpo-secure-storeへ保存、Tauriはwebview内でWebセッションを再利用——すべて同じBetter Authインスタンスが検証します。決済も同じ規則です。8つのWebゲートウェイとRevenueCatモバイルIAPが1つの冪等webhook台帳に流れ込み、全面が読むワークスペース単位のエンタイトルメントを書き込みます。
クロスプラットフォームSaaSが破断する2つの継ぎ目
Web SaaSにモバイルアプリを溶接したチームに本当の痛みを聞くと、答えは決まってUIではありません。IDと金です。ブラウザでは綺麗に戻るOAuthフローが、アプリへはディープリンクで戻らなければならず、Webで支払った顧客は自分の権限がすぐスマホに現れることを期待します。
チームはたいてい、2つの半分の解決策を出荷した後に気づきます。WKWebView内で静かに失敗するCookieロジックと、WebのDB内のStripeサブスクリプションと争うRevenueCatエンタイトルメント。修復は構造的であり、同じ修復を2度行います——1つのIDモデル、1つのエンタイトルメント保存先。
1つのBetter Authインスタンス、3つのセッション伝送
supastackは@supastack/authに単一のBetter Auth設定を持ち、面ごとのエントリーポイントを分けています。両Webアプリ(Next.js 16とTanStack Start)はHttpOnly、SameSite=LaxのCookieセッション——デフォルトでCSRF安全でServer Componentsと相性抜群です。Expoアプリはディープリンクコールバックの末尾でOAuthやマジックリンクの完了をBearerトークンに交換し、expo-secure-store(iOS Keychain / Android Keystore)に永続化して、Authorizationヘッダーで送信。同じ認証ミドルウェアが検証します。
TauriのデスクトップシェルはWebアプリを指す単一webviewなので、Webセッションをそのまま継承します——保守すべき第3の認証フローはありません。モバイル認証ガイドとディープリンクガイドにコールバック契約があり、Web + モバイル・モノレポガイドが共有クライアントコードを実演しています。
// 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.8つの決済ゲートウェイ、1つの契約
すべてのWeb決済プロバイダ——Stripe、Lemon Squeezy、Polar、Creem、Dodo、Paddle、Whop、PayPal——が同じ@supastack/billing契約に接続し、署名済みwebhookはすべて、権限に触れる前に1つの冪等webhook_event台帳へ記録されます。プロバイダの再試行や順序不同の配送は、データベース境界で無害なno-opになり、サポートチケットにはなりません。
モバイルのアプリ内課金はRevenueCat経由で同じ台帳に合流します。ストアレシートはサーバー側で検証され、権限はデバイスではなくワークスペースに書き込まれます——iOSで支払ったユーザーは、Webとデスクトップでも直ちに支払い済みです。RevenueCatガイドがApp Store / Playの配線を、冪等課金webhookが台帳が荷重部品である理由を解説します。
同期を退屈にするエンタイトルメントモデル
この状態が退屈でいられる理由は、権限がワークスペース上にありサーバー側で解決されるからです。「支払い済み」を保持するクライアントはありません——Webはセッションに、モバイルはAPIに、デスクトップはWebアプリに尋ね、三者は同じ答えを得ます。答えられるレコードが1つしかないからです。
新しいスマホでの購入復元、WebでのStripe更新、ダッシュボードでのAgencyシート追加——それぞれ同じ権限行への書き込みであり、各面は次に尋ねたときに読みます。同期すべきものが存在しないので、同期エンジンを作る必要がありません。
| 面 | セッション伝送 | 決済経路 | 権限の読み取り先 |
|---|---|---|---|
| Next.js 16 Web | HttpOnly Cookie | 8ゲートウェイのいずれか → webhook台帳 | 共有Postgres権限行 |
| TanStack Start Web | HttpOnly Cookie | 同じアダプター、同じ台帳 | 共有Postgres権限行 |
| Expo iOS / Android | expo-secure-store内のBearerトークン | RevenueCat IAP → サーバー検証レシート | 同じ行(型付きAPI経由) |
| Tauri 2デスクトップ | webview内のWebセッション | シェル内のWebチェックアウト | 同じ行(Webアプリ経由) |
| MV3拡張機能 | ワークスペースAPIキー | —(ワークスペースデータの読み取り) | 同じ行(/api/v1経由) |
作らずに済むもの
夜間作業で換算すれば、これが基盤と機能リストの差です。ディープリンク認証の戻り、SecureStoreトークン永続化、リプレイ安全な8つのwebhook統合、App Storeレシート検証、デバイス間で矛盾しない権限モデル。すべて出荷済み・テスト済み(693+テストが資格情報なしで実行可能)・文書化済みです。
$299のFull Bundleは全ての面を1リポジトリに含みます——シート数とエージェンシーティアは価格ページで。
FAQ:クロスプラットフォームの認証・決済共有
統一スタックにコミットする前にチームが尋ねる質問:
- モバイルユーザーはWebとは別にログインしますか?, いいえ。OAuthやマジックリンクのフローはディープリンクでアプリに戻り、1つのセッションを発行します。発行者は同じBetter Authインスタンスなので、Webとモバイルで「あなたは誰か」の答えが一致します。
- iOSで支払ってWebアプリを使う人は?, RevenueCatがサーバー側で購入を配達します。権限はWebが読む同じワークスペース行に書き込まれ、Webアプリは次のリクエストで支払い済みを表示します。
- Webだけで始めて後からアプリを追加できますか?, はい。認証と課金は共有パッケージにあるため、モバイルとデスクトップはその面を有効化した時点で継承します。
- Tauriアプリに独自のチェックアウトは必要?, 不要です。デスクトップシェルはwebview内でWebアプリのセッションとチェックアウトを再利用し、守るべき第2の決済面は存在しません。