new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Better Auth · all subjects

client apis/expo

32 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Expo SDK 55 requirement and architecture

Better Auth Expo integration requires Expo SDK 55 (React Native 0.83, React 19.2). SDK 55 requires the New Architecture; the Legacy Architecture is no longer supported.

Better Auth backend setup for Expo

Before using Better Auth with Expo, you must set up a Better Auth backend on a separate server or use Expo's API Routes feature to host the Better Auth instance. If using API Routes, create an API route at app/api/auth/[...auth]+api.ts that imports the Better Auth handler and exports it for both GET and POST requests.

Server dependencies for Expo integration

Install better-auth and @better-auth/expo packages on the server. Command: npm install better-auth @better-auth/expo

Client dependencies for Expo

Install better-auth, @better-auth/expo, and expo-network on the Expo client application. Command: npm install better-auth @better-auth/expo expo-network. For social providers (Google, Apple), also install expo-linking, expo-web-browser, and expo-constants. For secure session storage, install expo-secure-store.

Expo plugin configuration on server

Add the Expo plugin to the Better Auth server configuration by importing expo from @better-auth/expo and adding it to the plugins array. Example: betterAuth({ plugins: [expo()], emailAndPassword: { enabled: true } })

Initialize Better Auth client with Expo plugin

Call createAuthClient imported from better-auth/react with the baseURL of the Better Auth backend. Add the expoClient plugin from @better-auth/expo/client to the plugins array. The expoClient plugin enables social authentication flows and secure cookie management. Pass expo-secure-store as the storage mechanism.

Expo client initialization code example

Example of initializing the auth client: ```ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import * as SecureStore from "expo-secure-store"; export const authClient = createAuthClient({ baseURL: "http://localhost:8081", plugins: [ expoClient({ scheme: "myapp", storagePrefix: "myapp", storage: SecureStore, }) ] }); ```

Expo scheme configuration in app.json

Define the app scheme in the app.json file under the expo configuration. Example: { "expo": { "scheme": "myapp" } }. This scheme is used for deep links after OAuth authentication.

Better Auth trustedOrigins for Expo

Add the app scheme to the trustedOrigins list in the Better Auth server config. Example: betterAuth({ trustedOrigins: ["myapp://"] }). Supports multiple schemes, wildcards, and patterns. In development mode with Expo's exp:// scheme, you can use wildcard patterns like "exp://" or "exp://**". In production, use the specific app scheme like "myapp://".

Development mode trustedOrigins for Expo

During development, Expo uses the exp:// scheme with local IP addresses. To support this, configure trustedOrigins with conditional patterns: trustedOrigins includes "exp://", "exp://**", and "exp://192.168.*.*:*/**" when NODE_ENV is "development". These patterns should only be used in development, not in production.

Metro Bundler configuration for Better Auth

Better Auth relies on package.json exports to resolve modules. Expo SDK 53+ and SDK 55 enable package exports support by default in Metro, so no extra configuration is needed. If you have a custom metro.config.js, ensure you do not set config.resolver.unstable_enablePackageExports to false. After making changes to Metro config, clear cache with npx expo start --clear.

Email and password authentication in Expo

Use authClient.signIn.email() to sign in with email and password. Pass an object with email and password properties. Use authClient.signUp.email() to sign up with email, password, and name.

Email sign-up example for Expo

Example of email sign-up: ```tsx import { useState } from "react"; import { View, TextInput, Button } from "react-native"; import { authClient } from "@/lib/auth-client"; export default function SignUp() { const [email, setEmail] = useState(""); const [name, setName] = useState(""); const [password, setPassword] = useState(""); const handleLogin = async () => { await authClient.signUp.email({ email, password, name }) }; return ( <View> <TextInput placeholder="Name" value={name} onChangeText={setName} /> <TextInput placeholder="Email" value={email} onChangeText={setEmail} /> <TextInput placeholder="Password" value={password} onChangeText={setPassword} /> <Button title="Login" onPress={handleLogin} /> </View> ); } ```

Social sign-in for Expo

Use authClient.signIn.social() with the provider name and a callback URL. When you pass a relative path like "/dashboard", the Expo plugin automatically converts it to a deep link using Linking.createURL. On native (iOS/Android), signIn.social does not navigate automatically; handle navigation yourself after it resolves.

Social sign-in example for Expo

Example of social sign-in: ```tsx import { Button } from "react-native"; import { router } from "expo-router"; import { authClient } from "@/lib/auth-client"; export default function SocialSignIn() { const handleLogin = async () => { const { error } = await authClient.signIn.social({ provider: "google", callbackURL: "/dashboard" }) if (error) { return; } router.replace("/dashboard"); }; return <Button title="Login with Google" onPress={handleLogin} />; } ```

IdToken sign-in for Expo social providers

Use authClient.signIn.social() with the idToken option to verify an ID token obtained from the mobile device on the server. Pass an object with provider name, idToken containing token and optional nonce, and callbackURL. Supported providers for idToken sign-in are Google, Apple, and Facebook only.

IdToken sign-in example for Expo

Example of idToken sign-in: ```tsx import { Button } from "react-native"; export default function SocialSignIn() { const handleLogin = async () => { await authClient.signIn.social({ provider: "google", idToken: { token: "...", nonce: "...", }, callbackURL: "/dashboard" }) }; return <Button title="Login with Google" onPress={handleLogin} />; } ```

Google Sign-In with @react-native-google-signin example

Example of Google Sign-In using idToken and @react-native-google-signin/google-signin: ```tsx import { GoogleSignin, GoogleSigninButton, isSuccessResponse, } from "@react-native-google-signin/google-signin"; import { View } from "react-native"; import { router } from "expo-router"; import { authClient } from "@/lib/auth-client"; GoogleSignin.configure({ webClientId: process.env.EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID, iosClientId: process.env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID, }); export default function GoogleSignIn() { const handleGoogle = async () => { await GoogleSignin.hasPlayServices(); const response = await GoogleSignin.signIn(); if (isSuccessResponse(response) && response.data.idToken) { const { error } = await authClient.signIn.social({ provider: "google", idToken: { token: response.data.idToken }, }); if (!error) { router.replace("/dashboard"); } } }; return ( <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <GoogleSigninButton onPress={handleGoogle} /> </View> ); } ```

useSession hook for Expo

Better Auth provides a useSession hook to access the current user's session. Use authClient.useSession() and access the session data via the data property. Returns an object with session and user information.

useSession example for Expo

Example of using the useSession hook: ```tsx import { Text } from "react-native"; import { authClient } from "@/lib/auth-client"; export default function Index() { const { data: session } = authClient.useSession(); return <Text>Welcome, {session?.user.name}</Text>; } ```

Session caching in Expo SecureStore

On native platforms, session data is cached in SecureStore by default. This allows removing the need for a loading spinner when the app is reloaded. This behavior can be disabled by passing the disableCache option to the expoClient plugin.

Making authenticated requests in Expo

To make authenticated requests to your server that require the user's session, retrieve the session cookie from SecureStore using authClient.getCookie() and manually add it to request headers. Set credentials to "omit" to prevent interference with manually set cookies.

Authenticated fetch example for Expo

Example of making an authenticated request: ```tsx import { authClient } from "@/lib/auth-client"; const makeAuthenticatedRequest = async () => { const cookies = authClient.getCookie(); const headers = { "Cookie": cookies, }; const response = await fetch("http://localhost:8081/api/secure-endpoint", { headers, credentials: "omit" }); const data = await response.json(); return data; }; ```

TRPC integration with Expo authentication

Example of TRPC provider with authenticated requests: ```tsx import { authClient } from "@/lib/auth-client"; export const api = createTRPCReact<AppRouter>(); export function TRPCProvider(props: { children: React.ReactNode }) { const [queryClient] = useState(() => new QueryClient()); const [trpcClient] = useState(() => api.createClient({ links: [ httpBatchLink({ headers() { const headers = new Map<string, string>(); const cookies = authClient.getCookie(); if (cookies) { headers.set("Cookie", cookies); } return Object.fromEntries(headers); }, }), ], }), ); return ( <api.Provider client={trpcClient} queryClient={queryClient}> <QueryClientProvider client={queryClient}> {props.children} </QueryClientProvider> </api.Provider> ); } ```

expoClient plugin options reference

expoClient plugin configuration options: - storage: the storage mechanism used to cache the session data and cookies. Example: SecureStore - scheme: scheme used to deep link back to your app after OAuth authentication. By default, Better Auth reads from app.json. Can be overridden here. Example: "myapp" - disableCache: boolean to disable session data caching in SecureStore. Default: false - cookiePrefix: prefix or array of prefixes for server cookie names to identify which cookies belong to better-auth. Prevents infinite refetching with third-party cookies. Defaults to "better-auth". Can be a single string or array of strings.

expoClient storage option example

Example of configuring storage in expoClient: ```ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import SecureStorage from "expo-secure-store"; const authClient = createAuthClient({ baseURL: "http://localhost:8081", plugins: [ expoClient({ storage: SecureStorage, }) ], }); ```

expoClient scheme option example

Example of configuring scheme in expoClient: ```ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; const authClient = createAuthClient({ baseURL: "http://localhost:8081", plugins: [ expoClient({ scheme: "myapp", }), ], }); ```

expoClient disableCache option example

Example of disabling cache in expoClient: ```ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; const authClient = createAuthClient({ baseURL: "http://localhost:8081", plugins: [ expoClient({ disableCache: true, }), ], }); ```

expoClient cookiePrefix option example

Example of configuring cookiePrefix in expoClient: ```ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import * as SecureStore from "expo-secure-store"; const authClient = createAuthClient({ baseURL: "http://localhost:8081", plugins: [ expoClient({ storage: SecureStore, cookiePrefix: "better-auth" }) ] }); ```

expoClient multiple cookiePrefix example

Example of configuring multiple cookie prefixes in expoClient: ```ts const authClient = createAuthClient({ baseURL: "http://localhost:8081", plugins: [ expoClient({ storage: SecureStore, cookiePrefix: ["better-auth", "my-app", "custom-auth"] }) ] }); ```

Passkey plugin cookiePrefix integration with Expo

If using the passkey plugin with a custom webAuthnChallengeCookie option in Expo, include the cookie prefix in the expoClient cookiePrefix array. For example, if webAuthnChallengeCookie is "my-app-passkey", include "my-app" in the cookiePrefix array.

Expo server plugin disableOriginOverride option

Server plugin option for Expo: disableOriginOverride (default: false). Override the origin for Expo API routes. Enable this if facing CORS origin issues with Expo API routes.

Give your agent this brain