Documentation

Auth adapters

Auth is optional. Most apps launch without it. Add an adapter only when RevenueCat needs to know who your logged-in user is.

Do you need auth at all?

Probably not for your first paid version. RevenueCat creates an anonymous customer for every device, and Apple/Google handle restoring purchases on a new phone. Auth only matters when your app needs to recognize the same person across devices or on your server.

Skip auth if

  • Premium features unlock on the device itself
  • Users restore purchases through Apple/Google
  • You have no server-side, user-specific data

Add auth when

  • Users log in and sync data across devices
  • Firestore rules depend on a user id
  • Your backend needs to know who paid

Tip

You can always add auth later. Start anonymous, ship, and connect an adapter when a real need shows up. RevenueCat merges the anonymous purchase history into the logged-in user.
1

The entire contract is one function

An “adapter” sounds fancy, but it is just an object with one function that answers a single question: “Who is the current user?”

src/paywall-ready/authAdapter.ts

1export type PaywallReadyAuth = {2  getUserId: () => string | null | Promise<string | null>;3};

Good to know

How the provider uses it: If getUserId() returns a stable id, PaywallReady logs that user into RevenueCat so purchases follow them everywhere. If it returns null, RevenueCat keeps using an anonymous customer. That is the whole contract — no tokens, no sessions, no callbacks.
2

Pick the adapter that matches your stack

Choose exactly one of these. They all do the same thing: return your app’s stable user id, or null when nobody is logged in.

Option A — No auth (fastest launch)

App.tsx

1<PaywallReadyProvider2  iosApiKey={REVENUECAT_IOS_API_KEY}3  androidApiKey={REVENUECAT_ANDROID_API_KEY}4  entitlementId="pro"5>6  <App />7</PaywallReadyProvider>

Users can buy, unlock premium, and restore purchases through their store account — all with zero login screens.

Option B — Firebase Auth

firebaseAuthAdapter.ts

1import { getAuth } from "firebase/auth";2import { createAuthAdapter } from "./paywall-ready";3 4const firebaseAuthAdapter = createAuthAdapter(() => {5  return getAuth().currentUser?.uid ?? null;6});

Use this when your app already signs users in with Firebase — required if your Firestore rules check request.auth.uid.

Option C — Supabase

supabaseAuthAdapter.ts

1import { createAuthAdapter } from "./paywall-ready";2 3const supabaseAuthAdapter = createAuthAdapter(async () => {4  const { data } = await supabase.auth.getSession();5  return data.session?.user.id ?? null;6});

Use this when Supabase owns your logins. Return the Supabase user id — it stays stable for the lifetime of the account.

Option D — Clerk

clerkAuthAdapter.ts

1import { createAuthAdapter } from "./paywall-ready";2 3const clerkAuthAdapter = createAuthAdapter(() => {4  return user?.id ?? null; // from useUser()5});

Use this when Clerk handles login. RevenueCat only needs the stable Clerk user id, nothing else.

Option E — Your own backend

customAuthAdapter.ts

1import { createAuthAdapter } from "./paywall-ready";2 3const customAuthAdapter = createAuthAdapter(async () => {4  return (await mySession.load())?.userId ?? null;5});

Return whatever stable id your backend uses for the user. RevenueCat keys the customer to it — and the Firebase entitlement mirror relies on this same id.

Watch out

The id must be stable. Never return an email, a session token, or anything that can change. If the id changes, RevenueCat treats it as a different customer and the purchase history will look lost.
3

How to know it worked

Verify these after wiring the adapter

  • Logged-out users either stay anonymous or see your normal login flow.
  • Logged-in users appear in the RevenueCat dashboard with your app's user id.
  • Purchasing once unlocks the same entitlement after an app restart.
  • Logging in on a second device shows the same premium status.
  • Restore purchases still works after login.