Skip to content
LogoLogo

AuthBoundary

A component that simplifies protecting routes and content based on authentication state. It handles four distinct scenarios: loading, error, unauthenticated, and authenticated.

Usage

import { AuthBoundary } from '@openfort/react-native';
import { Text, ActivityIndicator } from 'react-native';
 
function App() {
  return (
    <AuthBoundary
      loading={<ActivityIndicator size="large" />}
      unauthenticated={<LoginScreen />}
      error={(error) => <Text>Error: {error.message}</Text>}
    >
      <AuthenticatedApp />
    </AuthBoundary>
  );
}

Props

type AuthBoundaryProps = {
  /** Component to render while the SDK is initializing */
  loading: React.ReactNode
  /** Component to render when the user is not authenticated */
  unauthenticated: React.ReactNode
  /** Optional component to render when there's an error during SDK initialization */
  error?: React.ReactNode | ((error: Error) => React.ReactNode)
  /** Children to render when the user is authenticated and the SDK is ready */
  children: React.ReactNode
}

States

The component handles four states:

StateConditionRenders
LoadingSDK is initializingloading prop
ErrorSDK encountered initialization errorerror prop (if provided)
UnauthenticatedUser is not logged inunauthenticated prop
AuthenticatedUser is logged in, SDK is readychildren

With React Navigation

A common pattern is to use AuthBoundary with React Navigation to show different navigation stacks based on authentication state:

import { AuthBoundary } from '@openfort/react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
 
const Stack = createNativeStackNavigator();
 
function App() {
  return (
    <NavigationContainer>
      <AuthBoundary
        loading={<SplashScreen />}
        unauthenticated={
          <Stack.Navigator>
            <Stack.Screen name="Login" component={LoginScreen} />
            <Stack.Screen name="Signup" component={SignupScreen} />
          </Stack.Navigator>
        }
      >
        <Stack.Navigator>
          <Stack.Screen name="Home" component={HomeScreen} />
          <Stack.Screen name="Profile" component={ProfileScreen} />
        </Stack.Navigator>
      </AuthBoundary>
    </NavigationContainer>
  );
}

With Expo Router

When using Expo Router, place the AuthBoundary in your root layout:

// app/_layout.tsx
import { AuthBoundary, OpenfortProvider } from '@openfort/react-native';
import { Slot } from 'expo-router';
import { ActivityIndicator, View } from 'react-native';
 
export default function RootLayout() {
  return (
    <OpenfortProvider
      publishableKey="YOUR_PUBLISHABLE_KEY"
      walletConfig={{
        shieldPublishableKey: "YOUR_SHIELD_KEY",
        createEncryptedSessionEndpoint: "https://your-backend.com/api/encryption-session"
      }}
    >
      <AuthBoundary
        loading={
          <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
            <ActivityIndicator size="large" />
          </View>
        }
        unauthenticated={<LoginScreen />}
      >
        <Slot />
      </AuthBoundary>
    </OpenfortProvider>
  );
}

Error Handling

The error prop can be either a static component or a function that receives the error:

// Static error component
<AuthBoundary
  loading={<LoadingScreen />}
  unauthenticated={<LoginScreen />}
  error={<Text>Something went wrong</Text>}
>
  <App />
</AuthBoundary>
 
// Dynamic error component
<AuthBoundary
  loading={<LoadingScreen />}
  unauthenticated={<LoginScreen />}
  error={(error) => (
    <View>
      <Text>Error: {error.message}</Text>
      <Button title="Retry" onPress={() => { /* retry logic */ }} />
    </View>
  )}
>
  <App />
</AuthBoundary>