Intro To Firebase ReactFire v4 - Login, Logout Create Account And Protected Routes

Aaron K Saunders - Mar 1 '22 - - Dev Community

Overview

This is a quick walkthrough of a code example using ReactFire v4 in an application. The application supports login, logout, create an account, and protected routes. We also walk through two approaches for protecting routes since the AuthCheck component that existed in v3 no longer exists in v4 of ReactFire.

This is an updated version of a previously released reactfire intro application and video that was working with v3; this new code will work with v4.

The source code for this video and the two approaches for protecting routes is available in the github repo

The code uses Ionic Framework for UI but the code is react so it should work in all reactjs based applications

Video

Code

I am using Firebase Emulator in my project, if you are going to do the same, be sure you are using node v16 otherwise you will run into issues Issue In StackOverflow

Login Code

We need the getAuth hook from reactFire

const auth = getAuth();
Enter fullscreen mode Exit fullscreen mode

then we use the auth object to make the call to sign in with the user credentials

  const doSignIn = () => {
    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        // Signed in
        const user = userCredential.user;
        console.log(user);
        history.push("/home");
        return true;
      })
      .catch(async (error) => {
        const errorCode = error.code;
        const errorMessage = error.message;

        await alert({
          header: "Error Signing In",
          message: errorMessage,
          buttons: ["OK"],
        });
      });
  };
Enter fullscreen mode Exit fullscreen mode

Create Account Code

We need the getAuth hook from reactFire

const auth = getAuth();
Enter fullscreen mode Exit fullscreen mode

then we use the auth object to make the call to create the user account using the user credentials

  const doCreateAccount = () => {
    createUserWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        // Signed in
        const user = userCredential.user;
        console.log(user);
        history.replace("/");
        return true;
      })
      .catch(async (error) => {
        const errorCode = error.code;
        const errorMessage = error.message;

        await alert({
          header: "Error Creating Account",
          message: errorMessage,
          buttons: ["OK"],
        });
      });
  };
Enter fullscreen mode Exit fullscreen mode

Sign Out Code

We need the getAuth hook from reactFire

const auth = getAuth();
Enter fullscreen mode Exit fullscreen mode

then we use the auth object to make the call to sign the user out

<IonButton
    onClick={async () => {
        await signOut(auth);
        history.replace("/login");
     }}>
     SIGN OUT
</IonButton>
Enter fullscreen mode Exit fullscreen mode

Two Approaches For Checking For Auth User

In both cases you will need to wrap all of the Routes with the AuthProvider and the FirestoreProvider

  return (
    <IonApp>
      <AuthProvider sdk={auth}>
        <FirestoreProvider sdk={firestoreDatabase}>

        ... Routes Go Here ...

        </FirestoreProvider>
      </AuthProvider>
    </IonApp>
  );
};
Enter fullscreen mode Exit fullscreen mode

PrivateRoute Component

Using the PrivateRoute Component, we setup our Router using the PrivateRoute component instead of the Route component for protected routes.

Note here we need to use the Ionic specific Router IonReactRouter but it can be replaced with ReactRouter in a react application

  <IonReactRouter>
    <IonRouterOutlet>
      <Route path="/" exact={true}>
        <Redirect to="/home" />
      </Route>
      <PrivateRoute path="/home" exact={true}>
        <Home />
      </PrivateRoute>
      <Route path="/login" exact={true}>
        <Login />
      </Route>
      <Route path="/create-account" exact={true}>
        <CreateAccount />
      </Route>
    </IonRouterOutlet>
  </IonReactRouter>
Enter fullscreen mode Exit fullscreen mode

From the react router documentation..

for this to work with IonicReactRouter, I had to remove the location from being passed in to the redirect as state. IonicRouter doesnt support Switch, so the thing just kept looping

// A wrapper for <Route> that redirects to the login
// screen if you're not yet authenticated.
export const PrivateRoute = ({
  children,
  location,
  ...rest
}: React.PropsWithChildren<any>) => {
  const { status, data: signInCheckResult } = useSigninCheck();
  console.log(signInCheckResult);
  debugger;
  if (status === "loading") {
    return <IonLoading isOpen={status === "loading"} />;
  }

  return (
    <Route
      {...rest}
      render={({ location }) =>
        signInCheckResult.signedIn === true ? (
          children
        ) : (
          <Redirect
            to={{
              pathname: "/login",
            }}
          />
        )
      }
    />
  );
};

Enter fullscreen mode Exit fullscreen mode

AuthWrapper Component

We need to set up the Router a bit differently here. You can see that we wrap all of our routes with AuthWrapper similar to what we did in v3 using the AuthCheck component.

  <AuthWrapper fallback={<AuthRoute />}>
    <Route path="/" exact={true}>
      <Redirect to="/home" />
    </Route>
    <Route path="/home" exact={true}>
      <Home />
    </Route>
  </AuthWrapper>
Enter fullscreen mode Exit fullscreen mode

We also need to point to the fallback route if there is no authenticated user. We have created a separate component that includes all of the non protected routes.

Note when using IonicReactRouter this code will not work properly since IonicReactRouter doesn't support Switch at the top level.

const AuthRoute = () => {
  return (
    <Switch>
      <Route path="/login" exact={true}>
        <Login />
      </Route>
      <Route path="/create-account" exact={true}>
        <CreateAccount />
      </Route>
      <Route path="*" exact={true}>
        <Redirect to="/login" />
      </Route>
    </Switch>
  );
};
Enter fullscreen mode Exit fullscreen mode

From the ReactFire Example Code, see this is in AppAuthWrapper.tsx. The AuthWrapper code is from the reactfire repo to account for the removal of AuthCheck component

export const AuthWrapper = ({
  children,
  fallback,
}: React.PropsWithChildren<{ fallback: JSX.Element }>): JSX.Element => {
  const { status, data: signInCheckResult } = useSigninCheck();
  console.log(signInCheckResult);

  if (!children) {
    throw new Error("Children must be provided");
  }
  if (status === "loading") {
    return <IonLoading isOpen={status === "loading"} />;
  } else if (signInCheckResult.signedIn === true) {
    return children as JSX.Element;
  }

  return fallback;
};

Enter fullscreen mode Exit fullscreen mode

Using Capacitor

when using capacitor you will need to initialize auth differently.

See bug - https://github.com/firebase/firebase-js-sdk/issues/5552#issuecomment-929580662

  const auth = initializeAuth(app, {
    persistence: indexedDBLocalPersistence
  });

  // browser only
  // const auth = getAuth(app);
Enter fullscreen mode Exit fullscreen mode

GitHub logo aaronksaunders / quick-intro-reactfire-v4

working with ionic framework and reacts with firebase, react fire and the latest version of firebase api

Quick Intro To ReactFire v4 Sample Application

Two Approaches For Checking For Auth User

From the react router documentation..

for this to work with IonicReactRouter, I had to remove the location from being passed in to the redirect as state. IonicRouter doesnt support Switch, so the thing just kept looping

// A wrapper for <Route> that redirects to the login
// screen if you're not yet authenticated.
export const PrivateRoute = ({
  children,
  location,
  ...rest
}: React.PropsWithChildren<any>) => {
  const { status, data: signInCheckResult } = useSigninCheck(
Enter fullscreen mode Exit fullscreen mode

Looking for support with your cross-platform mobile solution using Ionic Framework? Contact Me at my company Clearly Innovative Inc for a free 30-minute Consultation
www.clearlyinnovative.com

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .