Skip to main content
Better Auth supports both Expo native (iOS/Android) and web apps. This guide covers setting up a Better Auth backend with Expo API Routes, initialising the client with secure cookie storage, handling social authentication, and managing sessions.
This guide targets Expo SDK 55 (React Native 0.83, React 19.2). SDK 55 requires the New Architecture — the Legacy Architecture is no longer supported. If you are upgrading from an older SDK, see the Expo SDK 55 upgrade guide.

Installation

1

Configure a Better Auth backend

Before using Better Auth with Expo, you need a Better Auth backend. You can use a separate server or host your Better Auth instance inside the Expo app using Expo API Routes.To use Expo API Routes, create a catch-all API route and export the handler for both methods:
app/api/auth/[...auth]+api.ts
For a standalone server setup, follow the installation guide.
2

Install server dependencies

Install Better Auth and the Expo server plugin into your server (or Expo) project:
3

Install client dependencies

Install Better Auth and the Expo client plugin into your Expo application:
If you plan to use social providers (Google, Apple, etc.), you also need:
4

Add the Expo plugin on your server

Add the expo server plugin to your Better Auth instance:
lib/auth.ts
5

Initialise the Better Auth client

Create the auth client with createAuthClient from better-auth/react and add the expoClient plugin. The plugin handles secure cookie storage via expo-secure-store and manages OAuth browser sessions.
lib/auth-client.ts
Include the full URL with path if you changed the default /api/auth base path.
The expoClient plugin:
  • Enables social auth flows by handling OAuth URLs and callbacks in the Expo web browser.
  • Stores session cookies securely in expo-secure-store and appends them to auth request headers automatically.
6

Configure scheme and trusted origins

Better Auth uses deep links to redirect users back to your app after OAuth. Add your app scheme to trustedOrigins in your auth config.First, define the scheme in app.json:
app.json
Then add it to your Better Auth config:
lib/auth.ts
For development, Expo uses the exp:// scheme with your device’s local IP. You can conditionally allow it:
lib/auth.ts
The exp:// wildcard patterns should only be used in development. In production, use your app’s specific scheme (myapp://).
7

Configure Metro bundler

Better Auth relies on package.json exports for module resolution. From Expo SDK 53+, package exports are enabled in Metro by default — no extra configuration is needed.If you have a custom metro.config.js, ensure you are not disabling package exports:
metro.config.js
Clear the Metro cache after any config change:

Usage

Sign-in and sign-up

app/sign-in.tsx

Social sign-in

Pass a relative callback path to signIn.social. On native, the Expo plugin automatically converts it to a deep link using Linking.createURL.
app/social-sign-in.tsx
On native (iOS/Android), signIn.social does not navigate automatically. Handle navigation yourself after the call resolves. Browser behaviour differs by platform — see the Expo WebBrowser docs.

IdToken sign-in

If you obtain an ID token from a native provider SDK, you can verify it server-side with signIn.social and the idToken option:
app/social-sign-in.tsx

Session

Use the useSession hook to access the current user’s session reactively. On native, the session is cached in SecureStore to avoid a loading spinner on app restart.
app/index.tsx

Making authenticated requests

To send authenticated requests from native, retrieve the session cookie from SecureStore and attach it manually to your request headers.

Client options

storage

The storage mechanism used to persist session data and cookies. Defaults to expo-secure-store.
lib/auth-client.ts

scheme

The deep link scheme used to redirect back to your app after OAuth. By default, Better Auth reads this from app.json. Override it when necessary.

disableCache

Set to true to prevent session data from being cached in SecureStore.

cookiePrefix

Prefix (or array of prefixes) used to identify Better Auth cookies. Prevents infinite refetching when third-party cookies are present. Defaults to "better-auth".
If you use plugins with custom cookie names (e.g. webAuthnChallengeCookie), include the corresponding prefix in the cookiePrefix array. See the Passkey plugin docs for details.