Google SignIn in react-native using firebase auth
Tags: reactnative, firebase, typescript, javascript
Published: 2024-06-13 19:14:42

> 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](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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fikwv29mgu4dzn8rj7v6.png)

Note down your `Web client ID`.

![Not down the web client ID](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dwqw8xajqrlw7eu9yq14.png)

Once it's done it should look like:

![It will show Google as enabled](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6zkp372vd45huh7mhn2.png)

## 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
```

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
    }, []);

```

```
// 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,
    });
```

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

```
// 3a. onGoogleButtonPress

    async function onGoogleButtonPress() {
        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 });
            // Get the users ID token
            const { idToken, user, serverAuthCode } = await GoogleSignin.signIn(); // returns type: User
            const { id, name, email, photo, familyName, givenName } = user;

            console.log('serverAuthCode: ', serverAuthCode);
            console.log('idToken: ', idToken);

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

            // Sign-in the user with the credential
            return auth().signInWithCredential(googleCredential);
        } catch (error) {
            console.error('ERROR: ', error);
            return null;
        }
    }

```

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

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

```

// 3b. renderGoogleSigninButton

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>
        )
    }
```
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,
                });
            });
    });
}

```

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>
            )
        }
    }

```


```
// 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>
)

```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7op71vzkdhwom2xjf1wt.png)

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

![I am logged in](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qeubkx9puxgmpyx8mkeu.png)

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

![Takes me to google sign in page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gmei0gnjxuv9d57riwo6.png)

Logout test and it works as expected.

![Logout Test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/26r2rp69on7369azurrt.png)


### Errors

If you're getting this error:

```
 LOG  ERROR:  [Error: DEVELOPER_ERROR]
 LOG  ERROR:  10 DEVELOPER_ERROR
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sjpmaqk62245az5g074k.png)

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

```
cd android && ./gradlew signingReport
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z79qa2te2g4pqm3vuusz.png)

This solves the `10 DEVELOPER_ERROR`.

---


If you're getting:

```
[Error: SIGN_IN_REQUIRED]
```

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