How to create a secure and user-friendly email/password login and onboarding flow with Firebase in React Native Expo

113 Views Asked by At

I am building a mobile app with React Native, Expo and using Firebase as my database. Note that I am using the Firebase module and not @react-native-firebase. Let me give you an introduction about how my app currently works. In the App.js file,

// App.js
useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        setInitialScreen("Home");
      } else {
        setInitialScreen("Welcome");
      }
    });
  }, []);

This is how I check if the user is signed in already or no, if the user is signed in then I set the initial screen state to Home, or else I set it to Welcome. This initialState screen is used in the definition of my React Navigation. This is how I am creating the React Navigation now,

// App.js
// Earlier Contents and logics
return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName={initialScreen}>
        <Stack.Screen
          name="Welcome"
          component={Welcome}
          options={{ headerShown: false }}
        ></Stack.Screen>
        <Stack.Screen
          name="SignUp"
          component={SignUp}
          options={{ headerShown: false }}
        ></Stack.Screen>
        <Stack.Screen
          name="Login"
          component={Login}
          options={{ headerShown: false }}
        ></Stack.Screen>
        <Stack.Screen
          name="EmailVerificationPending"
          component={EmailVerificationPending}
          options={{ headerShown: false }}
        ></Stack.Screen>
      </Stack.Navigator>
    </NavigationContainer>
  );

Okay this is all about my current application. Not let me tell you what I want to do. In my Sign Up page, I have a form with 4 input fields, they are email, display name, password, and confirm password. Whenever the user enters all the information and clicks the Create Account button, an email is sent to their inbox containing an email verification link. This is how I am implementing this,

// SignUp.js
try {
 await sendEmailVerification(user);
 props.navigation.replace("EmailVerificationPending");
 } catch (error) {
  Alert.alert("Error sending email verification", error.message, [
  { text: "Ok" },
 ]);
}

This will send an email verification to the users email and redirect them to the Email Verification Pending page. But, after the verification email is sent I want to open a 3 screen on boarding. Here is what I plan to do for now, First of all, the user inputs all their information and clicks the Create Account button, then the user should be redirected to the 1st page of the on boarding session which says something like Verify your email from inbox. From that page, they cannot go back (the navigation should be something like they will just exit the app if they press back button in their phone). The user will see this message and then close the app, go to their email and click on the verification url. Aftter they have clicked the verification url their email will be verified (I have implemented this). So after their email is verified they will open my app, here comes the first issue. Since their email is created, the App.js file will find them as logged in user and try to send them to the Home page. But I don't want that to happen, instead I want the user to go to the 2nd on boarding screen, from there they can go back to the previous on boarding but since they are already verified the page will say "email address verified". But they cannot go back past the 1st on boarding screen. Okay, so after they have completed the 2nd on boarding page they will go to the 3rd on boarding page and from there they will go to the homepage. Once they have come to the homepage they cannot go back to any other screen (the on boarding, welcome screen or the sign up screen). Can someone guide me to do all the things above?

1

There are 1 best solutions below

0
On

When using React Navigation, I've found it's easiest to completely separate out the "authenticated" and "not authenticated" routes so it'll look something like this:

// App.js

export const App = () => {
  const isLoggedIn = useLoggedIn();
  const hasFinishedOnboarding = useHasFinishedOnboaring();
  
  if (isLoggedIn && hasFinishedOnboarding) {
    return <AppNavigator />
  }
  
  return <OnboardingNavigator />

}

So you'll need to store two values: isLoggedIn and hasFinishedOnboarding. You can do this either in with React Context or Redux, whichever you prefer.