Google SignIn in react-native using firebase auth
Chaudhry Talha 🇵🇸
Posted on June 13, 2024
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
onAuthStatusChanged
usingauth
from@react-native-firebase/auth
to check the current status of the user authentication. - Configure
GoogleSignin
usingGoogleSignin.configure
where we'll providewebClientId
which you should have at the time of the firebase console side configuration. - Handle
onGoogleButtonPress
andrenderGoogleSigninButton
as we'll be creating our own button to trigger aGoogleSignin
request. - Once a user is logged in then rendering a
renderLogoutView
andreturn
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(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
signOut
usingauth
- 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 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.
Posted on June 13, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.