Skip to content
Blog / Setting up route protection in React Native
4 min

Setting up route protection in React Native

Learn how to set up route protection in a React Native application using Appwrite.

Setting up route protection in React Native

In this guide, we'll walk through implementing protected routes in React Native using a simplified authentication approach with hardcoded values. The implementation uses a straightforward application structure that's easy to follow along with.

While you can start from scratch, we recommend having a basic React Native project already set up. If you need help with the initial setup, refer to our React Native Appwrite SDK Tutorial below:

Prerequisites

Before we begin, you should have:

  • A React Native project with Appwrite integration - Follow our quick start guide to set it up
  • Basic understanding of React Native and navigation concepts

Step 1: Setting up the file structure

First, we'll separate our routes into two categories: protected (which requires authentication) and public. We'll create this separation by wrapping our protected routes in a folder called (app):

src
├── app
│   ├── _layout.tsx    // Root layout
│   └── signin.tsx     // Public route

└── (app)           // Protected routes group
    ├── _layout.tsx    // Protected layout
    └── index.tsx      // Protected home screen

To protect the routes in our protected route group, we'll add an auth check within the protected route group's _layout.tsx file. For now, we'll use a hardcoded session value to keep things simple:

// app/(app)/_layout.tsx
import { Slot, Redirect} from "expo-router";

export default function AppLayout() {
  const session = false

  return !session ? <Redirect href="/signin"/> : <Slot/>
}

This is as simple as it gets - we're just blocking users from accessing any route that uses this layout if there's no session. However, in a real scenario, we want to pull the user state from some sort of provider, which we'll set up next.

Step 2: Creating our auth context

Let's create our auth context that we'll use throughout the app:

TypeScript
// app/context/AuthContext.js
import { useContext, createContext, useState, useEffect } from 'react';
import { Text, SafeAreaView } from 'react-native';

const AuthContext = createContext()

const AuthProvider = ({children}) => {
    const [user, setUser] = useState(false)
    const [session, setSession] = useState(false)
    const [loading, setLoading] = useState(true)

    const signIn = async () => {}
    const signOut = async () => {}

   const contextData = {
       user,
       session,
       signIn,
       signOut
   }

  return (
         <AuthContext.Provider value={contextData}>
            {loading ? <SafeAreaView>
                    <Text>Loading...</Text>
                </SafeAreaView> : children}
          </AuthContext.Provider>
         )
}

export {AuthContext, AuthProvider}

const useAuth = () => {return useContext(AuthContext)}

export {useAuth}

Step 3: Setting up the root layout

To use our auth context, we'll wrap the root layout with the AuthProvider:

TypeScript
import { Slot } from 'expo-router';
import { AuthProvider } from './context/AuthContext.js';

export default function Root() {
  return (
    <AuthProvider>
      <Slot />
    </AuthProvider>
  );
}

Build fast, scale faster

Backend infrastructure and web hosting built for developers who ship.

  • Start for free
  • Open source
  • Support for over 13 SDKs
  • Managed cloud solution

Step 4: Implementing protected routes

Now let's create our protected layout that will guard our private routes:

TypeScript
// app/(app)/_layout.tsx
import { Slot, Redirect} from "expo-router";
import {useAuth} from '../context/AuthContext.js'

export default function AppLayout() {
  const {user, session} = useAuth()

  return !session ?  <Redirect href="/signin"/> : <Slot/>
}

Step 5: Setting up the sign-in page

Finally, let's handle the case where an authenticated user tries to visit the sign-in page:

// app/signin.tsx
import { Redirect } from 'expo-router'
import { useAuth } from '@/context/AuthContext'
import { SafeAreaView, Text } from 'react-native'

const signin = () => {
  const {session} = useAuth()

  if (session) return <Redirect href="/"/>

  return (
    <SafeAreaView>
      <Text>signin</Text>
    </SafeAreaView>
  )
}

export default signin

This completes our implementation of protected routes in React Native. You now have a foundation for managing authenticated and public routes using React Context to handle the global session state.

Now that you have a basic route protection system in place, you can enhance it by implementing actual authentication logic using Appwrite. If you run into any issues or have questions, the Appwrite community on Discord is always ready to help.

More resources

If you would like to learn more about React Native and Appwrite, we have some resources that you should visit:

Frequently asked questions

  • How do I structure protected and public routes in Expo Router?

    Group protected routes inside a folder like (app) and keep public routes (sign-in, sign-up) outside it. The route group gets its own _layout.tsx that performs the auth check and redirects to the sign-in screen if there is no active session, so the protection lives in one place instead of every screen.

  • Where should the auth check live?

    Inside the protected group's _layout.tsx. Read the session from your auth context and either render the Slot (when authenticated) or Redirect to the sign-in screen (when not). This runs before any child route mounts, so unauthenticated users never see protected content.

  • How do I share auth state across screens in React Native?

    Use React Context. Create an AuthProvider that exposes user, session, signIn, and signOut, wrap your root layout with it, and consume the context via a useAuth hook from any screen. This keeps the session in one source of truth and avoids prop drilling.

  • How do I handle the loading state while restoring a session?

    Track a loading flag in your auth provider that is true until you have finished checking for an existing session on app start. Render a splash or loader while loading is true so users do not see a flicker between public and protected routes during cold start.

  • How does Appwrite fit into this flow?

    Appwrite Auth manages users and sessions on the backend. Your React Native app calls Appwrite to create or restore a session, and you set that session in your auth context. The route protection logic stays the same, only the signIn, signOut, and session-restore methods talk to Appwrite.

  • What happens to deep links when a user is not authenticated?

    Because the route group's layout intercepts any unauthenticated access and redirects to sign-in, deep links into protected routes will also bounce to the sign-in screen. To send users back to the original deep link after login, capture the intended path before redirecting and navigate to it once a session is established.

Start building with Appwrite today