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.
Note down your Web client ID.
Once it's done it should look like:
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
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:
- Checking onAuthStatusChangedusingauthfrom@react-native-firebase/authto check the current status of the user authentication.
- Configure GoogleSigninusingGoogleSignin.configurewhere we'll providewebClientIdwhich you should have at the time of the firebase console side configuration.
- Handle onGoogleButtonPressandrenderGoogleSigninButtonas we'll be creating our own button to trigger aGoogleSigninrequest.
- Once a user is logged in then rendering a renderLogoutViewandreturnmain 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(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;
  }
}
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>
        )
    }
The step 4, let's divide it into smaller parts:
- Implement signOutusingauth
- implement a renderLogoutViewto implement logout.
- Main screen Componentsthat 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 logged in, so it shows the Logout button:
It'll take user to Google Sign In page for verification.
Logout test and it works as expected.
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:
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.
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.
 
 
              









 
    
Top comments (0)