Native apps

Expo in 5 minutes

Install the SDK and native session storage:

bun add @aussieljk/auth @better-auth/expo
npx expo install expo-secure-store expo-web-browser

Scaffold the client, layout provider, sign-in route, and app scheme:

bunx aussieauth init expo --scheme myapp

Set environment variables:

EXPO_PUBLIC_AUSSIEAUTH_URL=https://your-deployment.convex.site
EXPO_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud

Register the native origins with the AussieAuth deployment:

bunx aussieauth apps register \
  --auth-url "$EXPO_PUBLIC_AUSSIEAUTH_URL" \
  --secret "$AUSSIEAUTH_SECRET" \
  --slug myapp \
  --name "My App" \
  --scheme myapp \
  --dev-exp

Use the native card in app/sign-in.tsx:

import { AussieAuthNativeSignIn } from "@aussieljk/auth/native";
import { router } from "expo-router";
import { authClient } from "../lib/auth-client";

export default function SignIn() {
  return <AussieAuthNativeSignIn authClient={authClient} onSignedIn={() => router.replace("/")} />;
}

Protect routes with the Expo helpers:

import { RequireAuth } from "@aussieljk/auth/expo";
import { authClient } from "../lib/auth-client";

export default function Home() {
  return <RequireAuth authClient={authClient}>{/* app */}</RequireAuth>;
}

See examples/expo-router for a complete Expo Router app.

What the SDK provides

  • createAussieAuthExpoClient builds the Better Auth client with AussieAuth's methods, the Expo cookie/session bridge, cross-domain auth, and Convex token support.
  • AussieAuthProvider wraps the usual Expo app setup: native auth client plus ConvexBetterAuthProvider.
  • AussieAuthNativeSignIn is a React Native sign-in surface using ScrollView, TextInput, and Pressable rather than DOM/CSS.
  • RequireAuth, RedirectIfSignedIn, useAussieUser, and signOutAndRedirect cover the common route flows.
  • aussieauth apps register registers myapp:// and optionally exp:// with the existing /apps/register endpoint.

No Origin header

A native app has no Origin header, so @better-auth/expo sends its deep-link scheme as expo-origin and the server-side expo() plugin rewrites it back onto the request.

Everything downstream — CSRF, trustedOrigins, appMethods, the session's appId — then works unchanged.

The plugin has a second job on OAuth callbacks: it appends the session cookie to the myapp:// redirect, because a native app has no cookie jar the browser can write to.

Scheme origins

Native apps register scheme origins rather than URLs:

{
  "slug": "myapp",
  "name": "My App",
  "origins": ["myapp://", "exp://"]
}

Only the bare scheme is accepted, because these match by prefix.

That's what makes Expo Go work: its origin is exp://<lan-ip>:8081/--/, which changes with the network and so can never be registered exactly.

Prefix matching is confined to non-http origins. Doing it for web origins would mean https://myapp.com claiming https://myapp.com.evil, and registration refuses a bare https:// for the same reason.

Production notes

Trusting exp:// means any Expo Go project can reach the deployment. Use it for development deployments, not production.

Passkeys shared with the website need APPLE_APP_SITE_ASSOCIATION set and a real bundle id. Expo Go runs as Expo's bundle id, so associated-domain behavior only applies to development or production builds.

Read this page as markdown: /docs/native.md
Your apps talk to this server directly — no AussieAuth consent screen, ever.