Facebook OAuth using Firebase in React Native

zolomohan

Mohan Raj

Posted on May 5, 2021

Facebook OAuth using Firebase in React Native

In this tutorial, we will learn how to authenticate users with their Facebook accounts using the authentication module in Firebase in a Non-Expo React Native application.

To learn more about Firebase, refer to this link.

Prerequisites

We will not cover the basics of React and React Native in this tutorial. If you are not comfortable with the basics, we highly recommended going over this tutorial before you continue further.

Overview

We'll be going through these steps in this article:

  1. Development environment.
  2. Cloning the starter code.
  3. Setting up the Firebase project.
  4. Setting up Facebook App
  5. Setting up Firebase Authentication.
  6. Sign-in
  7. Display authenticated screen
  8. Sign out
  9. Recap

Development environment

IMPORTANT - We will not be using Expo in our project.

Follow this documentation to set up the development environment.

Make sure you're following the React Native CLI Quickstart, not the Expo CLI Quickstart.

env_setup.png

Cloning the starter code

Clone the starter code from this GitHub repository.

You can check out the final code from this GitHub Repository.

This will be the folder structure of the application.

folder_structure.png

I've set up 2 screens in the screens/ directory:

  • Authentication.js: Screen with a Facebook Sign-in button to initiate the sign-in process.

  • Authenticated.js: Screen that the user can see only if he is logged in.

screens.jpg

Setting up the Firebase project

Head to the Firebase console, sign in to your account and Create a new project.

firebase_new.png

You'll be presented with the dashboard once you create the new project.

new_dashboard.png

Now, click on the Android icon to add an Android app to the Firebase project.

register_app.png

You'll need the package name of the application to register your application. You'll find the package name in the AndroidManifest.xml which is located in android/app/src/main/.

package_name.png

In the next step, you should download the google-services.json file and place it in the android/app directory.

This file contains configurations that'll enable your application to access firebase services.

download_services.json.png

In the next step, It'll ask you to add configurations to the build.gradle files.

First, add the google-services plugin as a dependency inside of your android/build.gradle file:

buildscript {
  dependencies {
    // ... other dependencies
    classpath 'com.google.gms:google-services:4.3.3'
  }
}
Enter fullscreen mode Exit fullscreen mode

Then, execute the plugin by adding the following to your android/app/build.gradle file:

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
Enter fullscreen mode Exit fullscreen mode

You need to perform some additional steps to configure Firebase for iOS. Follow this documentation to set it up.

Finally, let's install the @react-native-firebase/app package in our app to complete the set up for Firebase.

npm install @react-native-firebase/app
Enter fullscreen mode Exit fullscreen mode

Setting up Facebook App

Head to developers.facebook.com and create a developer account.

Go to the Apps section and create a new app.

create_app.png

Once you create an application, you will be greeted with the App Dashboard. Add the Facebook Login product to your app from the dashboard.

fb_dashboard.png

To find the App ID and the App secret, which will be required in the later steps, head to basic settings.

app_secret.png

Once you make a copy of it, scroll down until you find Add Platform.

add_platform.png

Once you click on it, Select Android.

Fill out the Package Name, which you can find the package name in the AndroidManifest.xml that is located in android/app/src/main/.

For the Class Name, fill it out as MainActivity.

For the Key Hash, you need to generate it using openSSL. You can download it from Google Code Archive.

Download the K version.

openssl.png

Once you've downloaded it, extract it and copy the folder to C:/.

Detect your keytool.exe, which can be found in the JDK directory inside the bin/ directory. The JDK is usually in a location like C:\Program Files\Java\jdk1.8.0_261\bin.

Now, inside the bin/ folder, run:

./keytool -exportcert -alias androiddebugkey -keystore "C:\Documents and Settings\Administrator.android\debug.keystore" | "C:\OpenSSL\bin\openssl" sha1 -binary |"C:\OpenSSL\bin\openssl" base64
Enter fullscreen mode Exit fullscreen mode

Output:

4iuaxR+bpCEhMEQslBTwAePpz74=
Enter fullscreen mode Exit fullscreen mode

Refer to this StackOverflow question for more details on how to generate a Key Hash.

fb_android_app.png

For iOS setup, refer to this Quick Start Guide.

Setting up Firebase authentication

Head to the authentication section in the dashboard and click on the Get Started button. This will enable the authentication module of your project.

auth_get_starterd.png

Then, enable Facebook authentication in the sign-in methods. Once you've enabled it, provide the App ID and the App secret from the Facebook Developer Console and press Save.

enable_fb_auth.png

To complete the setup, you should add the OAuth redirect URI to your Facebook app configuration. Copy the OAuth redirect URI and head to the Facebook Developer console.

Under Products, head to Settings in Facebook Login. Paste the redirect URI under Valid OAuth Redirect URIs in Client OAuth Settings.

redirect_uri.png

Now, let's head to the application and install the auth module.

Let's install the @react-native-firebase/auth package in our app.

npm install @react-native-firebase/auth
Enter fullscreen mode Exit fullscreen mode

Let's declare the dependency for the authentication module in the android/app/build.gradle file using the Firebase Android BoM

dependencies {
    // Add these lines
    implementation platform('com.google.firebase:firebase-bom:26.3.0')
    implementation 'com.google.firebase:firebase-auth'
}
Enter fullscreen mode Exit fullscreen mode

Next, let's install the React Native Facebook SDK.

npm install react-native-fbsdk
Enter fullscreen mode Exit fullscreen mode

In android/build.gradle, add mavenCentral() under repositories in buildscript:

buildscript {
    repositories {
        google()
        jcenter()

        // Add this line
        mavenCentral()
    }
}
Enter fullscreen mode Exit fullscreen mode

In android/app/build.gradle, add the following under dependencies:

implementation 'com.facebook.android:facebook-android-sdk:[5,6)'
Enter fullscreen mode Exit fullscreen mode

Now, you should add your Facebook App ID to your project's strings file in android/app/res/values/strings.xml.

<resources>
  <string name="app_name">RNFirebaseFacebookAuth</string>
  <string name="facebook_app_id"><-- Your App ID here --></string>
</resources>
Enter fullscreen mode Exit fullscreen mode

In the AndroidManifest.xml file, add a uses-permission element under manifest: (Ignore if already present)

<uses-permission android:name="android.permission.INTERNET" />
Enter fullscreen mode Exit fullscreen mode

Next, add a meta-data to the application element:

<application android:label="@string/app_name" ...>
    ...
    <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/facebook_app_id"/>
    ...
</application>
Enter fullscreen mode Exit fullscreen mode

Follow this Getting Started Guide to set up the SDK for iOS.

Sign-in

In App.js, let's create a function called signIn that will be called when the user presses the Sign in button. Let's wrap all the code inside the function in a try/catch block to display any error that may arise during the sign in flow.

async function signIn() {
  try {

    // Code goes here

  } catch (error) {
    alert(error);
  }
}
Enter fullscreen mode Exit fullscreen mode

Let's use the Login Manager to log in with permissions. We need to pass an array of permissions that the app needs to the function.

const result = await LoginManager.logInWithPermissions([
  'public_profile',
  'email',
]);
Enter fullscreen mode Exit fullscreen mode

If the result contains an isCancelled property, it means the user cancelled the process. Let's throw an error which will then be handled by the catch block.

if (result.isCancelled) {
  throw 'User cancelled the login process';
}
Enter fullscreen mode Exit fullscreen mode

Once signed in, we should get the users AccessToken.

const data = await AccessToken.getCurrentAccessToken();
Enter fullscreen mode Exit fullscreen mode

If the data is empty, let's throw an error.

if (!data) {
  throw 'Something went wrong obtaining access token';
}
Enter fullscreen mode Exit fullscreen mode

Now, we should create a credential using the access token and sign in the user into the app.

const facebookCredential = auth.FacebookAuthProvider.credential(data.accessToken);
return auth().signInWithCredential(facebookCredential);
Enter fullscreen mode Exit fullscreen mode

Here is the complete code for the signIn function:

async function signIn() {
  try {
    // Login the User and get his public profile and email id.
    const result = await LoginManager.logInWithPermissions([
      'public_profile',
      'email',
    ]);

    // If the user cancels the login process, the result will have a 
    // isCancelled boolean set to true. We can use that to break out of this function.
    if (result.isCancelled) {
      throw 'User cancelled the login process';
    }


    // Get the Access Token 
    const data = await AccessToken.getCurrentAccessToken();

    // If we don't get the access token, then something has went wrong.
    if (!data) {
      throw 'Something went wrong obtaining access token';
    }

    // Use the Access Token to create a facebook credential.
    const facebookCredential = auth.FacebookAuthProvider.credential(data.accessToken);

    // Use the facebook credential to sign in to the application.
    return auth().signInWithCredential(facebookCredential);

  } catch (error) {
    alert(error);
  }
}
Enter fullscreen mode Exit fullscreen mode

Display authenticated screen

The onAuthStateChanged event will be triggered whenever the authentication state of the user changes inside the application.

You can set an event handler for this listener. This handler will receive the user object. If the user object is null, it means the user is signed-out, otherwise, they are signed-in.

You can access the current authenticated user's details using auth().currentUser from anywhere in the application. The user object will contain the displayName, email, and photoURL that were copied from Facebook to Firebase.

To learn more about the user object, refer to this documentation.

Let's create a state to track whether the user is authenticated or not. We should set the default value to false.

const [authenticated, setAutheticated] = useState(false);
Enter fullscreen mode Exit fullscreen mode

Let's set the authenticated state to true if the user object is not null in the onAuthStateChanged handler.

auth().onAuthStateChanged((user) => {
  if(user) {
    setAutheticated(true);
  }
})
Enter fullscreen mode Exit fullscreen mode

If the user is authenticated, we should display the Authenticated screen.

if (authenticated) {
  return <Authenticated />;
}
return <Authentication signIn={signIn} />;
Enter fullscreen mode Exit fullscreen mode

I'm using auth().currentUser in the Authenticated screen to display the email ID, name, and the user's profile picture.

const user = auth().currentUser;
return (
  <View style={styles.screen}>
    <Text style={styles.title}>You're Logged In</Text>
    <Image source={{ uri: user?.photoURL }} style={styles.image} />
    <Text style={styles.text}>{user?.displayName}</Text>
    <Text style={styles.text}>{user?.email}</Text>
    <View style={{ marginTop: 30 }}>
      <Button title="Signout" onPress={() => auth().signOut()} />
    </View>
  </View>
);
Enter fullscreen mode Exit fullscreen mode

signin.gif

Sign out

We should use the signOut method in the auth module to sign a user out from the application.

Let's import the auth module in Authenticated.js.

import auth from '@react-native-firebase/auth';
Enter fullscreen mode Exit fullscreen mode

Let's call the signOut method when the user presses the signout button.

<Button title="Signout" onPress={() => auth().signOut()} />
Enter fullscreen mode Exit fullscreen mode

Now, when the user presses the button, the auth module will sign the user out from the application. This will trigger the onAuthStateChanged listener. The handler will receive null instead of the user object.

Thus, we should set the authenticated state to false if we receive null.

auth().onAuthStateChanged((user) => {
  if(user) {
    setAuthenticated(true);
  } else {
    setAuthenticated(false);
  }
})
Enter fullscreen mode Exit fullscreen mode

signout.gif

Let's recap

  1. We set up our development environment and created a React Native app.
  2. We cloned the starter code.
  3. We created a Facebook app with a developer account and enabled Facebook Login for the app.
  4. We created a Firebase project and enabled Facebook authentication in our project with App ID and App Secret.
  5. We installed the required packages and we added the dependencies to the build.gradle files.
  6. We added the App ID to the strings.xml file and added some configurations to the AndroidManifest.xml file.
  7. We wrote a function to login the user with their Facebook access token using the Facebook SDK.
  8. We created a state to track the authentication state of the user and used the onAuthStateChanged handler to update the state.
  9. We displayed the Authenticated screen when the user had been authenticated.
  10. We used the auth module to sign out the user from the application from the Authenticated screen.

Congratulations, 🥳 You did it.

Thanks for reading.

Happy coding!

💖 💪 🙅 🚩
zolomohan
Mohan Raj

Posted on May 5, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related