Логотип Аурабаза
аурабазадокументы
документы›Путеводители›Экспо/React Native

Use Aurabase in an Expo / React Native app

Create the client with EXPO_PUBLIC_* variables, keep the session across app restarts, sign users in with a provider through a deep link, and subscribe to database changes.

5 мин читать·Уровень средний·Пересмотрено 22 окт. 2026 г.
Эта страница пока недоступна на вашем языке. Оно показано на английском языке.
Этот текст на английском языке был создан автоматически на основе французского оригинала и еще не проверялся.
#
Статус

1. What was verified

@aurabase/aurabase-js bundles without error for Android in an Expo project (npx expo export --platform android, Expo SDK 58, React Native 0.88). Running the app on a device or a simulator has not been verified yet: treat the session and realtime examples below as the intended usage, and report anything that differs.

Aurabase has no Flutter or Dart package on pub.dev yet: for Flutter, call the REST API (see REST API).

#
Setup

2. Install and configure

terminalbash
npx expo install expo-secure-store
npm install @aurabase/aurabase-js

Expo exposes to the app only the variables whose name starts with EXPO_PUBLIC_. Put the project URL and the anon key (never the service_role key: it would ship inside the app) in .env:

.envbash
EXPO_PUBLIC_AURABASE_URL=https://<slug>.aurabase.cloud
EXPO_PUBLIC_AURABASE_ANON_KEY=aura_anon_…
#
Session

3. Keep the session

On the web the SDK keeps the session in localStorage; React Native has none. Give the client an auth store that writes the session to expo-secure-store. The store is read at start-up, before the client is created:

lib/aurabase.tstypescript
import * as SecureStore from 'expo-secure-store'
import { BaseAuthStore, createClient } from '@aurabase/aurabase-js'
import type { User } from '@aurabase/aurabase-js'

const KEY = 'aurabase-session'

class SecureStoreAuthStore extends BaseAuthStore {
  override save(token: string, refreshToken: string, user: User): void {
    super.save(token, refreshToken, user)
    void SecureStore.setItemAsync(KEY, JSON.stringify({ token, refreshToken, user }))
  }

  override clear(): void {
    super.clear()
    void SecureStore.deleteItemAsync(KEY)
  }
}

/** Read the saved session once, at app start, before rendering anything that needs it. */
export async function createAuraClient() {
  const store = new SecureStoreAuthStore()
  const saved = await SecureStore.getItemAsync(KEY)
  if (saved) {
    const { token, refreshToken, user } = JSON.parse(saved) as {
      token: string
      refreshToken: string
      user: User
    }
    store.save(token, refreshToken, user)
  }
  return createClient(
    process.env.EXPO_PUBLIC_AURABASE_URL!,
    process.env.EXPO_PUBLIC_AURABASE_ANON_KEY!,
    { auth: { storage: store } },
  )
}
Внимание

Keep the stored value small. The code of expo-secure-store does not enforce a size limit, but the platform keystores are not designed for large values: if your session carries a lot of user metadata and save fails on a device, keep only the tokens, or use @react-native-async-storage/async-storage (less protected).

#
OAuth

4. Sign in with a provider

OAuth in a mobile app uses the system browser and comes back to the app through a deep link. Use the PKCE flow: the code that comes back is useless without the secret the app kept.

  1. Declare the app scheme in app.json ("scheme": "myapp"), then add the redirect URL in Studio › Authentication › Configuration › Redirect URLs. In a production build it is myapp://auth-callback; in Expo Go it is the exp://… address that Linking.createURL('auth-callback') prints, so add that one while developing.
  2. Create the client with auth: { storage: store, flowType: 'pkce' } (the createClient call above), install the two Expo modules, then start the flow and exchange the code:
terminalbash
npx expo install expo-web-browser expo-linking
lib/signInWithProvider.tstypescript
import * as Linking from 'expo-linking'
import * as WebBrowser from 'expo-web-browser'
import type { AuraClient } from '@aurabase/aurabase-js'

export async function signInWithProvider(aura: AuraClient, provider: 'google' | 'github') {
  const redirectTo = Linking.createURL('auth-callback')
  // On React Native the SDK does not redirect: it returns the URL to open.
  const { data, error } = await aura.auth.signInWithOAuth(provider, { redirectTo })
  if (error || !data) return { error }

  const result = await WebBrowser.openAuthSessionAsync(data.url, redirectTo)
  if (result.type !== 'success') return { error: new Error('Sign-in cancelled') }

  // The server redirects to redirectTo?code=… ; exchange the code for a session.
  const code = Linking.parse(result.url).queryParams?.code
  if (typeof code !== 'string') return { error: new Error('No code in the redirect') }
  return aura.auth.exchangeCodeForSession(code)
}

The PKCE secret (code_verifier) stays in memory while the system browser is open. If the system kills the app during sign-in, the exchange returns no_code_verifier: start the flow again.

To sign in with the native Google or Apple dialog instead of a browser, get an ID token from the provider's SDK and call aura.auth.signInWithIdToken('google', idToken). The client ID it is checked against is the one configured for the provider in Studio › Authentication › Providers.

#
В реальном времени

5. Realtime

React Native provides a WebSocket, which the SDK uses. A channel opened before the user signs in is re-authenticated when the session changes, so the order of subscribe() and signInWithPassword() does not matter.

components/Todos.tsxtypescript
import { useEffect } from 'react'
import type { AuraClient } from '@aurabase/aurabase-js'

export function useTodoChanges(aura: AuraClient, onChange: (type: string) => void) {
  useEffect(() => {
    const channel = aura.realtime
      .channel('todos')
      .on('postgres_changes', { event: '*', schema: 'public', table: 'todos' }, (change) =>
        onChange(change.eventType),
      )
      .subscribe((status) => {
        if (status === 'CHANNEL_ERROR') console.warn('realtime refused')
      })
    return () => {
      channel.unsubscribe()
    }
  }, [aura, onChange])
}
Последнее обновление · 22 окт. 2026 г.