Перейти к содержимому
Supastack
RU
Тема
ВойтиПолучить пожизненный доступ
Все статьи

Общая авторизация и 8 платёжных шлюзов для Next.js, Expo mobile и Tauri v2

Два самых сложных шва кроссплатформенного SaaS: deep-link-колбэк логина на мобайле и единый энтайтлмент для веб-платежей, RevenueCat IAP и десктопного чекаута. Как одно монорепо решает оба.

Noah Zixin Zhang3 мин чтения

Как делить авторизацию и платежи между Next.js, Expo и Tauri?

Зависит от того, удастся ли сохранить единую модель идентичности и единое хранилище энтайтлментов. Веб использует сессии на HttpOnly-cookie; Expo после deep-link OAuth-колбэка сохраняет bearer-токен в expo-secure-store; Tauri переиспользует веб-сессию в своём webview — всё это валидируется одним экземпляром Better Auth. Платежи по тому же правилу: 8 веб-шлюзов и RevenueCat IAP для мобайла вливаются в один идемпотентный журнал вебхуков, записывающий энтайтлменты уровня воркспейса, которые читает каждая поверхность.

Два шва, где кроссплатформенный SaaS рвётся

Спросите любую команду, приварившую мобильное приложение к веб-SaaS, где болит по-настоящему — ответ никогда не будет «UI». Это идентичность и деньги: OAuth-флоу, который в браузере возвращается чисто, должен вернуться в приложение через deep link; а клиент, заплативший на сайте, ждёт свой энтайтлмент в телефоне немедленно.

Команды обычно понимают это, выпустив два полурешения: логику cookie, которая тихо ломается внутри WKWebView, и энтайтлмент RevenueCat, воюющий со Stripe-подпиской в веб-БД. Починка архитектурная — и она одна и та же дважды: одна модель идентичности, одно хранилище энтайтлментов.

Один экземпляр Better Auth, три транспорта сессий

supastack держит единую конфигурацию Better Auth в @supastack/auth с точками входа по поверхностям. Оба веб-приложения (Next.js 16 и TanStack Start) используют сессии на HttpOnly-cookie SameSite=Lax — CSRF-безопасные по умолчанию и дружественные к Server Components. Expo-приложение в конце deep-link-колбэка обменивает завершение OAuth или magic link на bearer-токен, сохраняет его в expo-secure-store (iOS Keychain / Android Keystore) и отправляет в заголовке Authorization, валидируемом тем же auth-middleware.

Десктопная оболочка Tauri — единый webview, смотрящий на веб-приложение, поэтому наследует веб-сессию напрямую — никакого третьего auth-флоу для поддержки. Гид по мобильной авторизации и гид по deep links документируют контракт колбэка; наш гид по монорепо веб + мобайл показывает общий клиентский код.

// 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.

Восемь платёжных шлюзов, один контракт

Каждый веб-провайдер платежей — Stripe, Lemon Squeezy, Polar, Creem, Dodo, Paddle, Whop и PayPal — втыкается в один контракт @supastack/billing, и каждый подписанный вебхук сначала падает в идемпотентный журнал webhook_event, прежде чем ему разрешено трогать энтайтлменты. Ретраи провайдеров и внеочередные доставки становятся на границе БД безобидными холостыми операциями, а не тикетами в поддержку.

Мобильные встроенные покупки вливаются в тот же журнал через RevenueCat: чеки сторов верифицируются на сервере, а энтайтлменты пишутся на воркспейс, а не на устройство — заплативший на iOS сразу оплачен и на вебе, и на десктопе. Гид по RevenueCat описывает подключение App Store / Play; идемпотентные вебхуки биллинга объясняют, почему журнал — несущая деталь.

Модель энтайтлментов, делающая синхронизацию скучной

Почему всё остаётся скучным: энтайтлменты живут на воркспейсе и разрешаются на сервере. Ни один клиент не хранит состояние «оплачено» — веб спрашивает сессию, мобайл — API, десктоп — веб-приложение — и все трое получают один ответ, потому что отвечать может только одна запись.

Восстановление покупок на новом телефоне, продление Stripe на вебе, добавление места Agency в дашборде — каждое есть запись в одни и те же строки энтайтлментов, которые каждая поверхность читает при следующем запросе. Синхронизационный движок строить не нужно, потому что синхронизировать нечего.

ПоверхностьТранспорт сессииПуть платежаЭнтайтлменты читаются из
Next.js 16 webHttpOnly-cookieЛюбой из 8 шлюзов → журнал вебхуковОбщие строки энтайтлментов Postgres
TanStack Start webHttpOnly-cookieТе же адаптеры, тот же журналОбщие строки энтайтлментов Postgres
Expo iOS / AndroidBearer-токен в expo-secure-storeRevenueCat IAP → серверная проверка чекаТе же строки (через типизированный API)
Tauri 2 desktopВеб-сессия внутри webviewВеб-чекаут внутри оболочкиТе же строки (через веб-приложение)
MV3-расширениеВоркспейс-ключ API— (читает данные воркспейса)Те же строки (через /api/v1)

Что вам не придётся строить

В пересчёте на вечера работы это и есть разница между фундаментом и списком фич: возврат авторизации по deep link, персистентность токена в SecureStore, восемь replay-безопасных интеграций вебхуков, верификация чеков App Store и модель энтайтлментов, никогда не противоречащая себе между устройствами. Всё поставлено, протестировано (693+ тестов без учётных данных) и задокументировано.

Full Bundle за $299 содержит все поверхности в одном репо — количество мест и агентские тарифы на странице цен.

FAQ: общая авторизация и платежи между платформами

Вопросы команд перед выбором единого стека:

  • Мобильные пользователи логинятся отдельно от веба?, Нет. OAuth-флоу или magic link возвращается в приложение по deep link и выпускает ту же сессию; выпускает её тот же экземпляр Better Auth, так что веб и мобайл согласны в ответе на «кто вы».
  • Что если человек платит на iOS но пользуется веб-приложением?, RevenueCat доставляет покупку на сервере; энтайтлмент записывается в те же строки воркспейса, которые читает веб, и веб-приложение показывает «оплачено» со следующего запроса.
  • Можно ли начать только с веба и добавить приложения позже?, Да — авторизация и биллинг живут в общих пакетах, поэтому мобильное и десктопное приложения наследуют их, как только вы включаете эти поверхности.
  • Нужен ли Tauri-приложению собственный чекаут?, Нет — десктопная оболочка переиспользует сессию и чекаут веб-приложения внутри своего webview; второй платёжной поверхности для защиты нет.

Ваш следующий продукт начинается здесь.

Один платёж. Создавайте прибыльные продукты.