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.
Top comments (0)