Popular Searches
Popular Course Categories
Popular Courses

Implementing Authentication, Navigation, and Firebase Integration

Implementing Authentication, Navigation, and Firebase Integration

React Native Practical Projects, Portfolio, and Interview Preparation

Implementing Authentication, Navigation, and Firebase Integration in React Native

Course: React Native Training

Topic: Implementing Authentication, Navigation, and Firebase Integration

Course Link: React Native Training at JustAcademy

Demo Link: Register for a Course Demo

JustAcademy Website: Visit JustAcademy


1. Introduction

Authentication, navigation, and Firebase integration are essential parts of a modern React Native application. Authentication verifies a user's identity, navigation controls movement between application screens, and Firebase provides backend services such as user authentication, databases, file storage, and application monitoring.

These features work together to create applications in which users can register, sign in, access protected screens, manage their profiles, and securely interact with cloud data according to their permissions.

For example, a student management application may allow students to sign in and view their profiles, while authorized administrators can manage student records. An employee directory may allow employees to view colleagues while restricting editing and deletion to administrators.

1.1 What You Will Build

This module explains how to build a React Native application with the following capabilities:

  • User registration using email and password.
  • User sign-in and sign-out.
  • Firebase Authentication integration.
  • Navigation between authentication and application screens.
  • Protected screens that are available only to authenticated users.
  • Authentication-state persistence across app restarts.
  • Cloud data storage using Firebase Firestore.
  • Basic user profile management.
  • Loading indicators and error handling.
  • Security rules for protecting user data.

2. Understanding Authentication

Authentication is the process of verifying that a user is who they claim to be. In a mobile application, users commonly authenticate through an email and password, a phone number, or an identity provider such as Google.

2.1 Why Authentication Is Important

  • Restricts access to private application screens.
  • Identifies the current user.
  • Allows users to access their own profiles and records.
  • Supports account creation and account recovery.
  • Helps personalize the application experience.
  • Provides an identity that backend security rules can use when authorizing requests.

2.2 Authentication vs. Authorization

Authentication Authorization
Verifies the user's identity. Determines what the user is permitted to do.
Answers: Who are you? Answers: What can you access?
Example: Signing in with email and password. Example: Allowing only an administrator to delete student records.

A successful login does not automatically make a user an administrator. Authorization must be implemented separately through trusted backend logic, database rules, and carefully defined application permissions.

3. Understanding Navigation in React Native

Navigation allows users to move between screens. React Native provides the building blocks for user interfaces, while a navigation library such as React Navigation manages routes, navigation history, and screen transitions.

3.1 Common Navigation Types

Navigation Type Description Example
Stack Navigation Places screens in a navigable stack. Login to Home to Profile.
Tab Navigation Provides persistent navigation tabs. Home, Directory, and Settings.
Drawer Navigation Displays a side navigation menu. Dashboard, Employees, Reports.
Conditional Navigation Displays different screens based on application state. Login screen when signed out and Home when signed in.

3.2 Authentication-Based Navigation

Authentication-based navigation separates the app into two main screen groups:

  • Authentication screens: Sign In, Sign Up, Forgot Password, and Reset Password.
  • Application screens: Home, Profile, Dashboard, Directory, and Settings.

When the user signs in, the application switches to the authenticated screen group. When the user signs out, it returns to the authentication screen group. This prevents users from navigating back to private screens through ordinary navigation history after signing out.

4. Introduction to Firebase

Firebase is Google's application development platform. It provides managed services that help developers build applications without implementing every backend feature from scratch.

4.1 Important Firebase Services

Service Purpose Example Use
Firebase Authentication Manages user identity and authentication. Registering and signing in users.
Cloud Firestore Stores structured documents in collections. Saving user profiles and directory records.
Realtime Database Stores JSON data with realtime synchronization. Applications requiring realtime updates.
Cloud Storage for Firebase Stores files such as images and documents. Uploading profile photographs.
Cloud Messaging Supports push messaging. Sending application notifications.
Crashlytics Collects crash reports. Investigating production crashes.

For this project, Firebase Authentication manages accounts and Cloud Firestore stores application records. Other services can be added when the application requires them.

5. Project Requirements and Setup

5.1 Required Tools

  • Node.js and npm.
  • Expo or a React Native development environment.
  • Android emulator, iOS simulator, or a compatible physical device.
  • A Google account to create a Firebase project.
  • A code editor such as Visual Studio Code.
  • Internet access during installation and Firebase configuration.

5.2 Create a React Native Project with Expo

npx create-expo-app SecureDirectoryApp
cd SecureDirectoryApp
npx expo start

This creates a starter application and starts the development server. Follow the terminal instructions to open the app on a simulator or supported device.

5.3 Install React Navigation

npm install @react-navigation/native
npm install @react-navigation/native-stack
npx expo install react-native-screens react-native-safe-area-context

Use the installation instructions for the navigation version in your project. If you choose a different navigation library or a different React Native setup, the installation steps may vary.

5.4 Install Firebase and AsyncStorage

npm install firebase
npx expo install @react-native-async-storage/async-storage

This example uses the Firebase JavaScript SDK. AsyncStorage is used as the persistence adapter for Firebase Authentication on React Native when configured with the compatible SDK version.

6. Creating a Firebase Project

Before connecting Firebase to React Native, create and configure a Firebase project.

6.1 Create the Project

  1. Open the Firebase Console.
  2. Sign in with your Google account.
  3. Create a new Firebase project.
  4. Follow the setup steps shown in the console.
  5. Add an application to the project using the appropriate configuration for your development setup.
  6. Open the project settings and locate the Firebase application configuration.

6.2 Enable Authentication

  1. Open the Firebase Console.
  2. Select Authentication from the Build section.
  3. Open the sign-in method settings.
  4. Enable Email/Password authentication.
  5. Save the configuration.

Firebase Authentication will now be able to process email-and-password registration and sign-in requests for the configured project.

6.3 Create a Firestore Database

  1. Open Firestore Database in the Firebase Console.
  2. Create the database for your project.
  3. Choose the appropriate deployment region.
  4. Configure database security rules before using real user data.

Do not leave production data accessible through broad test rules. Use a development-only configuration while learning and replace it with restrictive rules before deployment.

7. Organizing the Application Files

A well-organized folder structure makes authentication, navigation, and Firebase code easier to maintain.

SecureDirectoryApp/
├── App.js
├── src/
│   ├── firebase/
│   │   └── firebaseConfig.js
│   ├── context/
│   │   └── AuthContext.js
│   ├── navigation/
│   │   └── RootNavigator.js
│   ├── screens/
│   │   ├── LoginScreen.js
│   │   ├── RegisterScreen.js
│   │   ├── ForgotPasswordScreen.js
│   │   ├── HomeScreen.js
│   │   └── ProfileScreen.js
│   └── services/
│       └── userService.js

For a small demonstration, some of these files can be combined. In larger applications, separating navigation, authentication state, Firebase configuration, and screen UI helps prevent duplicated logic.

8. Configuring Firebase in React Native

The Firebase configuration connects the application to the Firebase project. The web configuration values identify the project and app; Firebase Authentication and Firestore security are enforced by Firebase services and their rules.

8.1 Create the Configuration File

Create src/firebase/firebaseConfig.js and add the Firebase project configuration obtained from the Firebase Console.

import { initializeApp, getApp, getApps } from "firebase/app";
import {
  initializeAuth,
  getReactNativePersistence
} from "firebase/auth";
import AsyncStorage from "@react-native-async-storage/async-storage";
import { getFirestore } from "firebase/firestore";

const firebaseConfig = {
  apiKey: "YOUR_FIREBASE_API_KEY",
  authDomain: "YOUR_PROJECT_ID.firebaseapp.com",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_PROJECT_ID.firebasestorage.app",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_FIREBASE_APP_ID"
};

const app = getApps().length ? getApp() : initializeApp(firebaseConfig);

let auth;

try {
  auth = initializeAuth(app, {
    persistence: getReactNativePersistence(AsyncStorage)
  });
} catch (error) {
  if (error.code === "auth/already-initialized") {
    const { getAuth } = require("firebase/auth");
    auth = getAuth(app);
  } else {
    throw error;
  }
}

const db = getFirestore(app);

export { app, auth, db };

Important implementation note: Replace the placeholder configuration values with the values from your Firebase project. Do not copy the placeholders literally. Firebase SDK initialization should occur once. In a modular JavaScript project, it is often cleaner to initialize the app and authentication instance in one module and import the resulting instances elsewhere.

The exact AsyncStorage import and persistence adapter depend on the versions of the Firebase JavaScript SDK and AsyncStorage in your project. If your installed Firebase version does not expose getReactNativePersistence as shown, follow the current Firebase Authentication documentation for the compatible React Native setup. Avoid initializing Firebase Auth twice.

8.2 Understanding the Configuration

  • apiKey: Identifies the Firebase project for client SDK requests; it is not a substitute for database security rules.
  • authDomain: Used by Firebase authentication flows that rely on the configured domain.
  • projectId: Identifies the Firebase project.
  • storageBucket: Identifies the project's Cloud Storage bucket where applicable.
  • messagingSenderId: Identifies the Firebase Cloud Messaging sender project.
  • appId: Identifies the registered Firebase application.

Firebase client configuration is not equivalent to a server secret. Never put service-account private keys, administrative credentials, or private backend secrets inside a mobile application.

9. Understanding Firebase Authentication Methods

Firebase Authentication provides SDK methods for common authentication workflows. The following table lists methods used in this module.

Method Purpose
createUserWithEmailAndPassword Creates an account using an email address and password.
signInWithEmailAndPassword Signs in an existing account.
signOut Signs out the current user.
onAuthStateChanged Observes changes to the signed-in user.
sendPasswordResetEmail Sends a password-reset email.
sendEmailVerification Sends an email verification message to the current user.
updateProfile Updates supported profile properties such as display name or photo URL.

10. Implementing User Registration

Registration creates a new Firebase Authentication account. The application should validate the input, call Firebase, and display a useful result.

10.1 Registration Workflow

  1. The user opens the registration screen.
  2. The user enters a name, email address, and password.
  3. The application validates required fields.
  4. The application submits the credentials to Firebase Authentication.
  5. Firebase creates the account if the request is valid and permitted.
  6. The app displays an appropriate result.
  7. The authentication-state listener updates the application when the user becomes signed in.

10.2 Example Registration Function

import {
  createUserWithEmailAndPassword,
  updateProfile,
  sendEmailVerification
} from "firebase/auth";
import { auth } from "../firebase/firebaseConfig";

export async function registerUser(name, email, password) {
  const cleanName = name.trim();
  const cleanEmail = email.trim().toLowerCase();

  if (!cleanName || !cleanEmail || !password) {
    throw new Error("Complete all required fields.");
  }

  if (password.length < 8) {
    throw new Error("Use a password with at least 8 characters.");
  }

  const credential = await createUserWithEmailAndPassword(
    auth,
    cleanEmail,
    password
  );

  await updateProfile(credential.user, {
    displayName: cleanName
  });

  await sendEmailVerification(credential.user);

  return credential.user;
}

This example demonstrates a basic email/password registration workflow. Firebase's password policy, email verification settings, and any organization-specific requirements should be configured according to the application's needs.

10.3 Registration Best Practices

  • Use a suitable email keyboard on mobile devices.
  • Provide a show/hide password control where appropriate.
  • Validate required fields before sending a request.
  • Handle errors from Firebase rather than assuming registration succeeded.
  • Prevent accidental repeated submissions while a request is in progress.
  • Do not log passwords or include them in analytics events.
  • Require email verification when the application needs verified email identities.

11. Implementing User Login

Login allows an existing user to authenticate with their registered credentials. Firebase checks the credentials and returns a user credential when authentication succeeds.

11.1 Login Function

import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from "../firebase/firebaseConfig";

export async function loginUser(email, password) {
  const cleanEmail = email.trim().toLowerCase();

  if (!cleanEmail || !password) {
    throw new Error("Enter your email and password.");
  }

  const credential = await signInWithEmailAndPassword(
    auth,
    cleanEmail,
    password
  );

  return credential.user;
}

11.2 Login Screen Example

import React, { useState } from "react";
import {
  View,
  Text,
  TextInput,
  Pressable,
  ActivityIndicator,
  Alert,
  StyleSheet
} from "react-native";
import { loginUser } from "../services/authService";

export default function LoginScreen({ navigation }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [loading, setLoading] = useState(false);

  const handleLogin = async () => {
    if (!email.trim() || !password) {
      Alert.alert("Missing information", "Enter your email and password.");
      return;
    }

    try {
      setLoading(true);
      await loginUser(email, password);
    } catch (error) {
      Alert.alert("Sign-in failed", "Check your details and try again.");
    } finally {
      setLoading(false);
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Welcome Back</Text>

      <TextInput
        style={styles.input}
        placeholder="Email address"
        value={email}
        onChangeText={setEmail}
        keyboardType="email-address"
        autoCapitalize="none"
        autoCorrect={false}
        accessibilityLabel="Email address"
      />

      <TextInput
        style={styles.input}
        placeholder="Password"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
        autoCapitalize="none"
        accessibilityLabel="Password"
      />

      <Pressable
        style={styles.button}
        onPress={handleLogin}
        disabled={loading}
      >
        {loading ? (
          <ActivityIndicator color="#FFFFFF" />
        ) : (
          <Text style={styles.buttonText}>Sign In</Text>
        )}
      </Pressable>

      <Pressable onPress={() => navigation.navigate("Register")}>
        <Text style={styles.link}>Create an account</Text>
      </Pressable>

      <Pressable onPress={() => navigation.navigate("ForgotPassword")}>
        <Text style={styles.link}>Forgot password?</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    padding: 24,
    backgroundColor: "#F5F7FA"
  },
  heading: {
    fontSize: 28,
    fontWeight: "700",
    marginBottom: 24
  },
  input: {
    borderWidth: 1,
    borderColor: "#CDD4DC",
    backgroundColor: "#FFFFFF",
    borderRadius: 8,
    padding: 13,
    marginBottom: 14
  },
  button: {
    backgroundColor: "#2457C5",
    padding: 14,
    borderRadius: 8,
    alignItems: "center"
  },
  buttonText: {
    color: "#FFFFFF",
    fontWeight: "700"
  },
  link: {
    marginTop: 18,
    color: "#2457C5"
  }
});

This screen calls the login service and does not manually navigate to the Home screen after success. The root authentication listener should control which screen group is displayed. This avoids inconsistent navigation when the authentication state changes asynchronously.

12. Handling Authentication Errors

Authentication can fail for several reasons, including invalid credentials, disabled accounts, network problems, or too many requests.

Error Situation Recommended Handling
Missing email or password Ask the user to complete the required fields.
Invalid credentials Display a neutral sign-in failure message.
Email already in use Explain that the address may already have an account and provide a sign-in option.
Weak password Explain the password requirements.
Network failure Offer a retry option.
Too many requests Ask the user to wait before retrying.
Account disabled Explain that access is unavailable and provide an appropriate support route.

Firebase error codes and account-enumeration protections can vary according to project configuration. Avoid exposing unnecessary account details or raw technical error messages to end users.

13. Implementing Password Reset

A password-reset flow allows users to recover access to an account without asking an administrator to know or manually change their password.

13.1 Password Reset Function

import { sendPasswordResetEmail } from "firebase/auth";
import { auth } from "../firebase/firebaseConfig";

export async function requestPasswordReset(email) {
  const cleanEmail = email.trim().toLowerCase();

  if (!cleanEmail) {
    throw new Error("Enter your email address.");
  }

  await sendPasswordResetEmail(auth, cleanEmail);
}

13.2 Password Reset Screen Behavior

  • Ask the user for their email address.
  • Validate that the field is not empty.
  • Call the password-reset function.
  • Display a neutral confirmation message.
  • Handle network or request errors gracefully.
  • Do not request or store the user's existing password.

Use neutral confirmation wording where appropriate so the screen does not unnecessarily reveal whether an account exists.

14. Implementing Sign-Out

Sign-out ends the user's authenticated session. The app should respond to Firebase's authentication-state change rather than only navigating to the login screen.

14.1 Sign-Out Function

import { signOut } from "firebase/auth";
import { auth } from "../firebase/firebaseConfig";

export async function logoutUser() {
  await signOut(auth);
}

14.2 Add a Sign-Out Button

import React, { useState } from "react";
import {
  Pressable,
  Text,
  Alert,
  ActivityIndicator
} from "react-native";
import { logoutUser } from "../services/authService";

export default function SignOutButton() {
  const [loading, setLoading] = useState(false);

  const handleSignOut = async () => {
    try {
      setLoading(true);
      await logoutUser();
    } catch (error) {
      Alert.alert("Unable to sign out", "Please try again.");
    } finally {
      setLoading(false);
    }
  };

  return (
    <Pressable onPress={handleSignOut} disabled={loading}>
      {loading ? (
        <ActivityIndicator />
      ) : (
        <Text>Sign Out</Text>
      )}
    </Pressable>
  );
}

When Firebase reports that the user is signed out, the root navigator should display the authentication screens. Do not simply hide a button or navigate away while leaving private data accessible elsewhere in the app.

15. Persisting Authentication State

Authentication persistence allows users to remain signed in after restarting the application, depending on the configured persistence mechanism and session state.

For the Firebase JavaScript SDK in React Native, configure Firebase Auth with the appropriate React Native persistence adapter. Do not assume that manually saving a user ID or a Boolean value such as isLoggedIn is sufficient to authenticate a user.

15.1 Why Use onAuthStateChanged?

The onAuthStateChanged listener observes when Firebase determines that a user has signed in or out. It also supports the initial restoration of authentication state when the application starts.

import { onAuthStateChanged } from "firebase/auth";
import { auth } from "../firebase/firebaseConfig";

const unsubscribe = onAuthStateChanged(auth, (user) => {
  if (user) {
    console.log("Authenticated user:", user.uid);
  } else {
    console.log("No authenticated user");
  }
});

// Call unsubscribe when the listener is no longer needed.

Use the listener in a React effect or an authentication provider. Avoid registering a new listener on every render, and unsubscribe when the component unmounts.

16. Creating an Authentication Context

React Context allows multiple screens to access shared authentication information without passing the same props through every component. It can expose the current Firebase user and a loading flag.

16.1 Example AuthContext

import React, {
  createContext,
  useContext,
  useEffect,
  useState
} from "react";
import { onAuthStateChanged } from "firebase/auth";
import { auth } from "../firebase/firebaseConfig";

const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);
  const [initializing, setInitializing] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
      setUser(currentUser);
      setInitializing(false);
    });

    return unsubscribe;
  }, []);

  return (
    <AuthContext.Provider value={{ user, initializing }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);

  if (!context) {
    throw new Error("useAuth must be used within AuthProvider");
  }

  return context;
}

16.2 Understanding the Context

  • user: Contains the current Firebase user when signed in, or null when signed out.
  • initializing: Indicates whether the initial authentication state is still being determined.
  • AuthProvider: Makes the authentication state available to child components.
  • useAuth: Provides a reusable hook for reading authentication context.

During initialization, show a loading screen instead of briefly displaying the wrong navigation group.

17. Implementing Authentication-Based Navigation

The root navigator should render one screen group when the user is signed out and another when the user is signed in.

17.1 Root Navigator Example

import React from "react";
import { ActivityIndicator, View } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";

import { useAuth } from "../context/AuthContext";
import LoginScreen from "../screens/LoginScreen";
import RegisterScreen from "../screens/RegisterScreen";
import ForgotPasswordScreen from "../screens/ForgotPasswordScreen";
import HomeScreen from "../screens/HomeScreen";
import ProfileScreen from "../screens/ProfileScreen";

const Stack = createNativeStackNavigator();

export default function RootNavigator() {
  const { user, initializing } = useAuth();

  if (initializing) {
    return (
      <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
        <ActivityIndicator size="large" />
      </View>
    );
  }

  return (
    <NavigationContainer>
      <Stack.Navigator>
        {user ? (
          <>
            <Stack.Screen
              name="Home"
              component={HomeScreen}
              options={{ title: "Dashboard" }}
            />
            <Stack.Screen
              name="Profile"
              component={ProfileScreen}
              options={{ title: "My Profile" }}
            />
          </>
        ) : (
          <>
            <Stack.Screen
              name="Login"
              component={LoginScreen}
              options={{ title: "Sign In" }}
            />
            <Stack.Screen
              name="Register"
              component={RegisterScreen}
              options={{ title: "Create Account" }}
            />
            <Stack.Screen
              name="ForgotPassword"
              component={ForgotPasswordScreen}
              options={{ title: "Reset Password" }}
            />
          </>
        )}
      </Stack.Navigator>
    </NavigationContainer>
  );
}

This conditional navigator pattern keeps the authentication and private screen groups separate. Confirm that the screen imports and route names match the actual files in your project.

17.2 Connect the Provider in App.js

import React from "react";
import { AuthProvider } from "./src/context/AuthContext";
import RootNavigator from "./src/navigation/RootNavigator";

export default function App() {
  return (
    <AuthProvider>
      <RootNavigator />
    </AuthProvider>
  );
}

17.3 Why Not Navigate Manually After Login?

Firebase authentication changes are asynchronous. If the login screen manually navigates to Home while the root navigation state still represents a signed-out user, the app can enter an inconsistent state.

Instead, let Firebase update the authentication state and allow the root navigator to render the correct screen group. This also makes sign-out, restored sessions, and account changes easier to manage.

18. Building the Home Screen

The Home screen is the starting point for authenticated users. It can show a welcome message, navigation options, a profile link, and a sign-out action.

import React from "react";
import { View, Text, Pressable, StyleSheet } from "react-native";
import { useAuth } from "../context/AuthContext";
import SignOutButton from "../components/SignOutButton";

export default function HomeScreen({ navigation }) {
  const { user } = useAuth();

  return (
    <View style={styles.container}>
      <Text style={styles.heading}>Welcome</Text>
      <Text style={styles.email}>
        {user?.email || "Signed-in user"}
      </Text>

      <Pressable
        style={styles.button}
        onPress={() => navigation.navigate("Profile")}
      >
        <Text style={styles.buttonText}>View Profile</Text>
      </Pressable>

      <SignOutButton />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    justifyContent: "center"
  },
  heading: {
    fontSize: 26,
    fontWeight: "700"
  },
  email: {
    marginVertical: 12
  },
  button: {
    padding: 14,
    borderRadius: 8,
    backgroundColor: "#2457C5",
    marginBottom: 16
  },
  buttonText: {
    color: "#FFFFFF",
    textAlign: "center",
    fontWeight: "700"
  }
});

Make sure the SignOutButton import path matches the location where you create that component. If you keep the sign-out button inside another file, adjust the import accordingly.

19. Implementing Firebase Firestore

Cloud Firestore is a cloud-hosted NoSQL database that stores documents inside collections. It is useful for storing user profiles, directory records, application settings, and other structured information.

19.1 Understanding Collections and Documents

Term Meaning Example
Collection A group of documents. users
Document A record containing fields. users/user-123
Field A value inside a document. displayName
Document ID An identifier for the document. Firebase Authentication UID

19.2 Store a User Profile

After a user registers, the application can create a Firestore document containing the additional profile information the app needs.

import {
  doc,
  setDoc,
  serverTimestamp
} from "firebase/firestore";
import { db } from "../firebase/firebaseConfig";

export async function saveUserProfile(user, extraData = {}) {
  if (!user?.uid) {
    throw new Error("A signed-in user is required.");
  }

  const profileRef = doc(db, "users", user.uid);

  await setDoc(profileRef, {
    uid: user.uid,
    email: user.email ?? null,
    displayName: user.displayName ?? "",
    ...extraData,
    updatedAt: serverTimestamp()
  }, { merge: true });
}

Use the Firebase Authentication UID as a stable link between the authenticated account and its profile document. Validate which fields may be written by the user, and do not allow client-provided values to assign administrative privileges.

19.3 Read a User Profile

import { doc, getDoc } from "firebase/firestore";
import { db } from "../firebase/firebaseConfig";

export async function getUserProfile(uid) {
  const profileRef = doc(db, "users", uid);
  const snapshot = await getDoc(profileRef);

  if (!snapshot.exists()) {
    return null;
  }

  return snapshot.data();
}

Before calling this function, confirm that the current user is authenticated. Firestore security rules must independently enforce which documents the user may read.

19.4 Update a User Profile

import {
  doc,
  updateDoc,
  serverTimestamp
} from "firebase/firestore";
import { db } from "../firebase/firebaseConfig";

export async function updateUserProfileData(uid, updates) {
  const profileRef = doc(db, "users", uid);

  await updateDoc(profileRef, {
    ...updates,
    updatedAt: serverTimestamp()
  });
}

Only allow the specific fields that the user is authorized to update. Do not pass arbitrary form objects to a privileged backend without validating them.

20. Creating a User Service

Keeping Firestore operations in a service file separates data access from screen design.

import {
  collection,
  addDoc,
  getDocs,
  query,
  orderBy,
  serverTimestamp
} from "firebase/firestore";
import { db } from "../firebase/firebaseConfig";

export async function createDirectoryRecord(record) {
  const recordsRef = collection(db, "directoryRecords");

  const docRef = await addDoc(recordsRef, {
    ...record,
    createdAt: serverTimestamp(),
    updatedAt: serverTimestamp()
  });

  return docRef.id;
}

export async function fetchDirectoryRecords() {
  const recordsRef = collection(db, "directoryRecords");
  const recordsQuery = query(recordsRef, orderBy("name", "asc"));
  const snapshot = await getDocs(recordsQuery);

  return snapshot.docs.map((document) => ({
    id: document.id,
    ...document.data()
  }));
}

The collection in this example is named directoryRecords. Configure its security rules before using it. Add appropriate validation, error handling, and permissions to create or retrieve records. Firestore may require an index for certain compound queries.

21. Designing Firestore Security Rules

Firestore security rules determine which authenticated users can read or write documents. Hiding screens in React Native does not protect database records by itself.

21.1 Example: Users Can Read and Edit Their Own Profile

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth != null
                  && request.auth.uid == userId;

      allow create: if request.auth != null
                    && request.auth.uid == userId
                    && request.resource.data.uid == userId;

      allow update: if request.auth != null
                    && request.auth.uid == userId
                    && request.resource.data.uid == resource.data.uid;

      allow delete: if false;
    }
  }
}

This is an illustrative starting point, not a complete production policy. It allows authenticated users to read and update their own profile document and denies profile deletion. A production policy should validate allowed fields, field types, immutable properties, and other requirements.

21.2 Example: Private Directory Collection

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /directoryRecords/{recordId} {
      allow read: if request.auth != null;
      allow write: if false;
    }
  }
}

This example permits any authenticated user to read directory records and blocks client writes. It is appropriate only if the intended design is read-only for authenticated users. To support administrators, implement a trustworthy role model and enforce it in the rules or through a secure backend. Never assume that a user is an administrator because the mobile app sends an isAdmin field.

22. Handling User Roles and Permissions

Many applications have different types of users. For example, a student portal may have students and administrators, while an employee directory may have employees and HR managers.

Role Example Permissions
Student View and update permitted personal details.
Employee View permitted directory information and personal profile details.
Teacher or Manager Access specific records needed for assigned responsibilities.
Administrator Manage records according to explicitly assigned privileges.

For a production system, store authoritative roles in a trusted backend or use Firebase custom claims where appropriate. Configure security rules to check those roles. The app may hide unavailable actions for a better user experience, but the backend must enforce the actual permissions.

23. Connecting Authentication to Firestore

Authentication and Firestore work together through the signed-in user's identity. After authentication, Firebase provides a UID that can be used to identify the user in database operations.

  1. The user creates an account or signs in.
  2. Firebase Authentication verifies the credentials.
  3. The app receives the authenticated user object.
  4. The app reads or creates the user's permitted profile document.
  5. Firestore evaluates security rules for each request.
  6. The app displays data only after the request succeeds.
  7. When the user signs out, the app switches back to the authentication screens and clears any private in-memory data that should no longer remain visible.

Do not rely on the UID alone as proof of permission to access another user's records. Database rules must verify the identity and the requested operation.

24. Loading and Error States

Authentication and Firebase requests are asynchronous. The app should communicate progress and handle failures rather than freezing the interface or assuming that a request succeeded.

Situation Recommended Behavior
Initial authentication check Show a loading screen until the user state is known.
Login in progress Disable repeated submission and show a progress indicator.
Registration succeeds Show the authenticated screen group or the required verification flow.
Network unavailable Display a retry option where appropriate.
Firestore request denied Explain that access is unavailable without revealing sensitive implementation details.
Profile not found Offer an appropriate profile setup or recovery workflow.
Sign-out fails Display a message and allow the user to retry.

25. Testing Authentication and Navigation

Testing verifies that the correct screens are shown for every authentication state and that users cannot access private data through unintended paths.

25.1 Authentication Test Cases

Test Case Action Expected Result
TC01 Register with valid details Firebase creates the account.
TC02 Register with invalid details A clear error appears and registration is not completed.
TC03 Sign in with valid credentials The authenticated screen group appears.
TC04 Sign in with invalid credentials The user remains on the authentication screen.
TC05 Request a password reset The app handles the request and displays a neutral result.
TC06 Restart the app with a valid persisted session The app restores the authenticated state.
TC07 Sign out The app returns to the authentication screen group.
TC08 Attempt to open a private route while signed out The private screen is not available through the configured navigator.

25.2 Firebase Test Cases

  • Read the current user's permitted profile document.
  • Attempt to read another user's private profile.
  • Attempt an unauthorized write.
  • Verify that database rules reject unauthorized requests.
  • Test network failures and permission-denied errors.
  • Verify that sign-out clears private screen state.
  • Check that user roles cannot be changed by an ordinary profile update.

Use Firebase Emulator Suite when appropriate to test authentication and database rules safely before deploying changes to production.

26. Common Problems and Troubleshooting

Problem Possible Cause Solution
Firebase app initialization error Incorrect configuration or duplicate initialization Check project settings and initialize the app only once.
Authentication state is lost after restart Persistence is not configured correctly Configure the supported React Native persistence adapter.
Login succeeds but Home does not appear Authentication listener or navigation condition is incorrect Verify AuthProvider, RootNavigator, and the user state.
App briefly shows the wrong screen Navigation renders before initial auth state is resolved Show a loading screen until initialization finishes.
Firestore returns permission denied Rules reject the requested operation Inspect the rules and verify the user's intended permissions.
User profile is missing Profile document was never created Implement a controlled profile creation workflow.
Registration works but profile update fails Firestore rules or network request fails Handle the failure and provide a retry or recovery path.
Navigation can return to a private screen Authentication screens and app screens share an incorrect stack design Use conditional screen groups based on Firebase auth state.
Firebase module cannot be imported Package missing or import path incorrect Check installation and file paths, then restart the development server if needed.

27. Security Best Practices

  • Use Firebase Authentication or another trusted identity provider instead of creating a custom password system.
  • Never store raw passwords in AsyncStorage, Firestore, or application state for later reuse.
  • Do not treat a locally stored login flag as proof of authentication.
  • Use restrictive Firestore security rules.
  • Validate data on the backend or through database rules, not only in the mobile interface.
  • Keep private service credentials out of the client application.
  • Use secure storage for sensitive local information when required.
  • Use email verification and password-reset features when appropriate.
  • Limit permissions according to user roles and the principle of least privilege.
  • Clear sensitive in-memory data when the user signs out.
  • Avoid exposing raw Firebase errors or private record information in production logs.
  • Review security rules and authentication settings before every production release.

28. Improving the Application

After the basic implementation works, the app can be expanded with additional features.

  • Google Sign-In: Allow users to authenticate with a supported identity provider.
  • Phone Authentication: Verify users through a phone-based workflow where supported.
  • Email Verification: Require verified email addresses for selected features.
  • Profile Editing: Let users update permitted profile fields.
  • Profile Pictures: Store photographs in Cloud Storage for Firebase and save the appropriate file reference in Firestore.
  • Role-Based Navigation: Display role-appropriate screens while enforcing permissions in backend rules.
  • Realtime Updates: Use Firestore listeners where live updates are needed.
  • Push Notifications: Add Firebase Cloud Messaging for relevant notifications.
  • Offline Handling: Design a suitable offline and synchronization strategy.
  • Account Deletion: Build a secure workflow for deleting or disabling accounts and related records.

29. Mini Project: Secure Student or Employee Portal

Project Title: Secure Student Management or Employee Directory App

Objective: Build a React Native app with Firebase Authentication, authentication-aware navigation, and Firestore-backed user data.

29.1 Functional Requirements

  • Register a user with an email address and password.
  • Sign in and sign out.
  • Provide a password-reset workflow.
  • Restore authentication state when the app starts.
  • Display a Home screen only for authenticated users.
  • Display a Profile screen with permitted user details.
  • Save and retrieve the profile from Firestore.
  • Protect records using Firestore security rules.
  • Show loading and error states.
  • Test invalid credentials and unauthorized database requests.

29.2 Suggested Screens

Screen Purpose
Login Authenticate an existing user.
Register Create a new account.
Forgot Password Request a password-reset email.
Home Display a welcome message and main navigation options.
Profile Display the current user's permitted profile data.
Directory Display records permitted by the user's role.
Settings Provide account preferences and sign-out.

29.3 Project Deliverables

  • Working React Native source code.
  • Firebase project configuration instructions.
  • Authentication and navigation implementation.
  • Firestore data model and security rules.
  • Test cases for sign-in, registration, sign-out, and permissions.
  • A README containing setup steps and known limitations.

30. Development Workflow

  1. Plan Requirements: Define the users, authentication methods, and protected resources.
  2. Create the Project: Set up React Native and install the required packages.
  3. Configure Firebase: Create the Firebase project and enable Authentication and Firestore.
  4. Build Authentication Services: Implement registration, login, password reset, and sign-out.
  5. Create Auth Context: Observe and share the Firebase authentication state.
  6. Build Navigation: Display authentication or private screens according to the current user state.
  7. Connect Firestore: Create, read, and update permitted user data.
  8. Write Security Rules: Enforce data access permissions independently of the UI.
  9. Handle Errors: Add loading indicators, validation, and recovery actions.
  10. Test: Verify authentication flows, screen transitions, and database permissions.
  11. Review Security: Check configuration, storage, logging, and access rules.
  12. Prepare for Release: Test release builds and document setup requirements.

31. Interview Questions and Answers

Q1. What is authentication in React Native?

Answer: Authentication verifies the identity of a user before allowing access to account-related features or protected resources.

Q2. What is Firebase Authentication?

Answer: Firebase Authentication is a managed service that provides account creation, sign-in, sign-out, and supported identity-provider integrations.

Q3. What is React Navigation?

Answer: React Navigation is a navigation library that manages movement between screens, navigation history, and common mobile navigation patterns.

Q4. What is authentication-based navigation?

Answer: It is a navigation design that displays authentication screens when the user is signed out and application screens when the user is signed in.

Q5. What is onAuthStateChanged?

Answer: It is a Firebase Authentication listener that notifies the application when the current authentication state changes.

Q6. Why use an AuthContext?

Answer: AuthContext makes shared authentication information available across components without passing the same props through every level of the component tree.

Q7. What is Firebase Firestore?

Answer: Cloud Firestore is a managed NoSQL database that stores structured data in collections and documents.

Q8. What is the difference between authentication and authorization?

Answer: Authentication verifies who a user is, while authorization determines what resources and operations that user is permitted to access.

Q9. Why are Firestore security rules important?

Answer: They enforce data access permissions at the database level. Hiding a screen or button in the mobile app does not prevent an unauthorized database request.

Q10. How can authentication persist after restarting the app?

Answer: Configure Firebase Authentication with the supported persistence mechanism for the React Native environment and observe the restored state through onAuthStateChanged.

Q11. Why should private screens not be shown before authentication initializes?

Answer: The initial authentication state may not be known immediately. A loading screen prevents a temporary display of the wrong screen group.

Q12. How should sign-out be implemented?

Answer: Call Firebase's signOut method and let the authentication-state listener update the root navigator. Clear any sensitive in-memory data that should no longer be visible.

Q13. Can Firebase configuration values be placed in a mobile app?

Answer: The Firebase client configuration is designed to identify the project, but database rules and authentication must protect resources. Private service-account credentials and server secrets must never be embedded in the app.

Q14. How should user roles be implemented?

Answer: Use a trusted backend or Firebase custom claims for authoritative roles, then enforce permissions through database rules or server-side checks.

Q15. What should happen if Firestore returns permission denied?

Answer: Handle the error gracefully, check the authenticated user's intended permissions and security rules, and do not bypass the rules to make the request succeed.

32. Quick Revision Checklist

  • Understand authentication and authorization.
  • Create and configure a Firebase project.
  • Enable Firebase Authentication.
  • Configure Firebase Auth persistence for React Native.
  • Implement registration and login.
  • Implement password reset and sign-out.
  • Observe authentication changes with onAuthStateChanged.
  • Create an AuthContext for shared user state.
  • Build conditional authentication navigation.
  • Display a loading screen during initialization.
  • Connect Firestore for profile or directory data.
  • Write restrictive Firestore security rules.
  • Handle loading, validation, and network errors.
  • Test authenticated and unauthenticated navigation flows.
  • Review user roles, sensitive data handling, and production security.

33. Conclusion

Implementing authentication, navigation, and Firebase integration brings together several core skills required for real-world React Native development. Firebase Authentication manages user identity, React Navigation organizes screen transitions, and Cloud Firestore stores data according to the application's access rules.

A reliable implementation uses authentication-state listeners, handles the initial loading state, separates public and private screen groups, and enforces data permissions in Firebase rather than relying on the user interface alone. Begin with email/password authentication and a protected Home screen, then add Firestore profiles, password recovery, user roles, and more advanced features.

To learn more, visit JustAcademy's React Native Training course, register for a course demo, and explore the JustAcademy website.

34. Official Learning Resources

whatsapp