Google SignIn in react-native using firebase auth

thechaudhrysab

Chaudhry Talha 🇵🇸

Posted on June 13, 2024

Google SignIn in react-native using firebase auth

If you're looking for a solution without firebase, I've a medium article for that: https://medium.com/@ibjects/google-signin-tutorial-for-react-native-81a57fb67b18

Straight-forward way of implementing a google sign-in in a react native app using firebase.

Firebase Console

Add Google from the Additional Providers.

Choose Google as option for auth providers

Note down your Web client ID.

Not down the web client ID

Once it's done it should look like:

It will show Google as enabled

React-Native

Let's install the required libraries:

yarn add @react-native-firebase/app @react-native-firebase/auth
yarn add @react-native-google-signin/google-signin
Enter fullscreen mode Exit fullscreen mode

For Android, clean the project and build once from android studio to avoid any unexpected errors.

Create a Login.tsx screen. There are a few things that work together here:

  1. Checking onAuthStatusChanged using auth from @react-native-firebase/auth to check the current status of the user authentication.
  2. Configure GoogleSignin using GoogleSignin.configure where we'll provide webClientId which you should have at the time of the firebase console side configuration.
  3. Handle onGoogleButtonPress and renderGoogleSigninButton as we'll be creating our own button to trigger a GoogleSignin request.
  4. Once a user is logged in then rendering a renderLogoutView and return main components.

Below is the code for Login.tsx broken down as per the number list above:

// 1. 

import auth, { FirebaseAuthTypes } from '@react-native-firebase/auth';

// other imports and code

    const [user, setUser] = React.useState<FirebaseAuthTypes.User | null>();

    function onAuthStatusChanged(user: FirebaseAuthTypes.User | null) {
        setUser(user);
    }

    useEffect(() => {
        const subscriber = auth().onAuthStateChanged(onAuthStatusChanged);
        return subscriber; // unsubscribe on unmount
    }, []);

Enter fullscreen mode Exit fullscreen mode
// 2. 

import { GoogleSignin } from "@react-native-google-signin/google-signin";

//... other imports and everything in 1.

    GoogleSignin.configure({
        webClientId: 'ADD_YOUR_KEY_HERE',
        offlineAccess: true,
    });
Enter fullscreen mode Exit fullscreen mode

If required, look for Web client ID reference above to know where to get it.

// 3a. onGoogleButtonPress

async function onGoogleButtonPress(user: FirebaseAuthTypes.User | null) {
  if (user) {
    // user is already logged in so no need to do anything
    return null;
  }

  try {
    // Check if your device supports Google Play
    await GoogleSignin.hasPlayServices({
      showPlayServicesUpdateDialog: true,
    });

    const { type, data } = await GoogleSignin.signIn();

    /**
     * @type can be "cancelled" in which can @data will be 'null'; 
     * If @type is "success" then @data will be:
     * user: {
            id: string;
            name: string | null;
            email: string;
            photo: string | null;
            familyName: string | null;
            givenName: string | null;
        };
        scopes: string[];
        idToken: string | null;
        serverAuthCode: string | null;
     */

    if (type === 'success') {
      // const { id, name, email, photo, familyName, givenName } = data.user;

      // Create a Google credential with the token
      const googleCredential = auth.GoogleAuthProvider.credential(data.idToken);

      // Sign-in the user with the credential
      return auth().signInWithCredential(googleCredential);
    } else if (type === 'cancelled') {
      // When the user cancels the flow for any operation that requires user interaction.
      return; // do nothing
    }
  } catch (error) {
    console.error('ERROR: ', error);
    return error;
  }
}

Enter fullscreen mode Exit fullscreen mode

With a simple GoogleSignin.signIn() it'll automatically handles everything.

Now we'll implement the google sign in button component:


// 3b. renderGoogleSigninButton

import {
    GoogleSignin, // already imported before
    isErrorWithCode,
    statusCodes,
} from "@react-native-google-signin/google-signin";

//... other code

const renderGoogleSigninButton = () => {

        const buttonTitle = user ? `Signed in as: ${user.displayName}` : 'Continue with Google'

        return (
            <Pressable style={styles.buttonContainer} onPress={() => onGoogleButtonPress().then((value: FirebaseAuthTypes.UserCredential | null) => {
                    // The onGoogleButtonPress will update the setUser state, so no action needed here
                if (value) {
                    console.log('value.additionalInnfo: ', value.additionalUserInfo);
                    console.log('value.user: ', value.user);
                }
            }).catch((error) => {
                if (isErrorWithCode(error)) {
                    switch (error.code) {
                        case statusCodes.SIGN_IN_CANCELLED:
                            // user cancelled the login flow
                            Alert.alert("User cancelled the login flow. Please try again.");
                            break;
                        case statusCodes.IN_PROGRESS:
                            // operation (eg. sign in) already in progress
                            Alert.alert("Sign In already in progress. Please wait.");
                            break;
                        case statusCodes.PLAY_SERVICES_NOT_AVAILABLE:
                            // play services not available or outdated
                            Alert.alert("Play services not available or outdated. Please update your play services.");
                            break;
                        default:
                            // some other error happened
                            Alert.alert("An unknown error occurred. Please try again later.");
                    }
                } else {
                    // an error that's not related to google sign in occurred
                    Alert.alert("An error that's not related to google sign in occurred. Please try again later.");
                }
            })}>
                <Text>{buttonTitle}</Text>
            </Pressable>
        )
    }
Enter fullscreen mode Exit fullscreen mode

The step 4, let's divide it into smaller parts:

  • Implement signOut using auth
  • implement a renderLogoutView to implement logout.
  • Main screen Components that include login and logout buttons
// 4a.Implement `signOut` using `auth`
// src/api/FirebaseAuthUtils.ts
import auth from '@react-native-firebase/auth';

export function userLogout(): Promise<string> {
    return new Promise((resolve, reject) => {
        auth()
            .signOut()
            .then(() => {
                resolve('Logout Successful');
            })
            .catch(error => {
                reject({
                    title: 'Error',
                    desc: error.message,
                });
            });
    });
}

Enter fullscreen mode Exit fullscreen mode

Created a new file in src/api/FirebaseAuthUtils.ts and added a logout function.

Everything below is in Login.tsx

// 4b. Implement a `renderLogoutView` to implement logout.

import { userLogout } from "../api/FirebaseAuthUtils";
//... other imports

    const renderLogoutView = () => {
        if (user) {
            return (
                <Pressable onPress={() => {
                    userLogout().then((message) => {
                        Alert.alert(message);
                    }).catch(error => {
                        Alert.alert(error.title, error.desc);
                    });
                }}>
                    <Text style={styles.buttonTitle}>Logout</Text>
                </Pressable>
            )
        }
    }

Enter fullscreen mode Exit fullscreen mode
// 4c. Main screen `Components` that include login and logout buttons

return (
        <ScrollView>
                {!user && <>
                    <Text style={styles.descriptionText}>
                        New or returning user, press{'\n'}
                        <Text style={styles.boldText}>Continue with Google
                        </Text> to continue
                    </Text>
                    {renderGoogleSigninButton()}
                </>}
                {renderLogoutView()}
        </ScrollView>
)

Enter fullscreen mode Exit fullscreen mode

That's all the code that is needed. Next let's test it.

Testing

I tested on simulator and device, it works.

I am not logged in, so it shows the Login button:

I am not logged in

I am logged in, so it shows the Logout button:

I am logged in

It'll take user to Google Sign In page for verification.

Takes me to google sign in page

Logout test and it works as expected.

Logout Test

Errors

If you're getting this error:

 LOG  ERROR:  [Error: DEVELOPER_ERROR]
 LOG  ERROR:  10 DEVELOPER_ERROR
Enter fullscreen mode Exit fullscreen mode

Add the SHA-1 and SHA-256. If you only have debug build then just add for that otherwise add total 4; 2 for debug and 2 for release:

SHA keys entry

Below is the command you can run to get all the available SHA fingerprints:

cd android && ./gradlew signingReport
Enter fullscreen mode Exit fullscreen mode

Scroll down to find > Task :app:signingReport. Here you can find all the available SHA fingerprints. I only have debug so for me release and debug keys are the same, so in the above screenshot you see only two SHA fingerprints.

how to find SHA-1 and SHA-256 of android app

This solves the 10 DEVELOPER_ERROR.


If you're getting:

[Error: SIGN_IN_REQUIRED]
Enter fullscreen mode Exit fullscreen mode

Make sure that your signOut is properly configured. Try deleting the app and installing again.

💖 💪 🙅 🚩
thechaudhrysab
Chaudhry Talha 🇵🇸

Posted on June 13, 2024

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

Sign up to receive the latest update from our blog.

Related