How to Add Google Authentication to Your React Native App?
A friendly step-by-step guide to implementing Google Sign-In with Firebase and Expo, complete with code examples and troubleshooting tips.
Hey there, friend! In this guide, we'll walk together through integrating Google Authentication into your React Native app with the help of Firebase and Expo. Whether you're looking to spice up your app's login or simply interested in adding a highly reliable authentication method, you're in the right place!
Table of Contents
- Table of Contents
- Introduction
- Prerequisites
- Firebase Setup
- Expo Configuration
- Secret Management
- Implementing the Authentication UI
- Building & Testing Your App
- Troubleshooting Tips
- Wrapping Up
- Persisting Authentication State
Introduction
Before diving deep, here's a quick overview of what we'll do:
- Set up a Firebase project and configure both iOS and Android apps.
- Configure Expo so that we can leverage dynamic settings.
- Manage secrets securely with Expo Application Services (EAS).
- Implement a Google Sign-In screen using a simple UI (we're keeping it clean and friendly!).
- Build a development version of your app to test everything end-to-end.
Let's jump in and make your app even cooler with Google authentication!
Prerequisites
Make sure you have these ready:
-
Node.js & npm installed
-
Expo CLI installed:
npm install -g expo-cli
-
A basic understanding of React Native and Expo
-
A Firebase account
-
Xcode (for iOS) and/or Android Studio (for Android)
You're all set? Great—let's continue!
Firebase Setup
1. Create a Firebase Project
- Head over to the Firebase Console and create a new project.
2. Add iOS & Android Apps to Firebase
iOS Configuration
- Register your app with a bundle identifier (e.g.,
com.yourcompany.appname
). - Download the
GoogleService-Info.plist
file. - (Don't worry about the extra setup—Expo will handle much of it for you.)
Android Configuration
-
Register your app with a package name (e.g.,
com.yourcompany.appname
). -
Generate the SHA-1 certificate using Expo EAS:
eas build:configure
-
Add the generated SHA-1 to your Firebase Android app configuration.
-
Download the
google-services.json
file.
Tip: Keep these files out of your source control (we'll handle them securely in the next section).
Expo Configuration
Let's get Expo to work its magic with our Firebase credentials!
-
Install Required Dependencies:
npx expo install @react-native-google-signin/google-signin expo-dev-client
-
Convert
app.json
toapp.config.js
:This allows you to dynamically reference environment variables.
// app.config.js export default { expo: { ios: { bundleIdentifier: "com.yourcompany.appname", googleServicesFile: process.env.GOOGLE_SERVICES_INFOPLIST }, android: { package: "com.yourcompany.appname", googleServicesFile: process.env.GOOGLE_SERVICES_JSON }, plugins: [ "expo-router", "@react-native-google-signin/google-signin" ] } };
-
Configure EAS Development Builds:
Create or update your
eas.json
:{ "build": { "development": { "developmentClient": true, "distribution": "internal", "ios": { "simulator": true } } } }
Secret Management
Now, securely upload your Firebase configuration files using Expo's secret management:
# For Android
eas secret:create --scope project --name GOOGLE_SERVICES_JSON --type file --value /path/to/google-services.json
# For iOS
eas secret:create --scope project --name GOOGLE_SERVICES_INFOPLIST --type file --value /path/to/GoogleService-Info.plist
This way, your sensitive data stays safe, and you don't commit it to your repository.
Implementing the Authentication UI
Let's create a friendly authentication screen. Save this as src/screens/AuthScreen.tsx
(or wherever you manage your screens):
// src/screens/AuthScreen.tsx
import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import { GoogleSignin, GoogleSigninButton } from '@react-native-google-signin/google-signin';
import { Card, CardContent, CardHeader, CardFooter, CardTitle, CardDescription } from '~/components/ui/card';
import { Avatar, AvatarImage, AvatarFallback } from '~/components/ui/avatar';
import { Button } from '~/components/ui/button';
import { Text } from '~/components/ui/text';
export default function AuthScreen() {
const [user, setUser] = React.useState<SignInSuccessResponse | null>(null);
const [error, setError] = React.useState<string | null>(null);
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
// Initialize Google Sign-In
GoogleSignin.configure({
webClientId: 'YOUR_WEB_CLIENT_ID',
scopes: ['email']
});
// Check for existing sign-in
checkCurrentUser();
}, []);
const checkCurrentUser = async () => {
try {
const isSignedIn = await GoogleSignin.hasPlayServices();
if (isSignedIn) {
const currentUser = await GoogleSignin.signInSilently();
setUser(currentUser);
}
} catch (error) {
if (error instanceof Error) {
setError(error.message);
}
} finally {
setIsLoading(false);
}
};
const signIn = async () => {
try {
await GoogleSignin.hasPlayServices();
const userInfo = await GoogleSignin.signIn();
setUser(userInfo);
} catch (e: any) {
setError(e.toString());
}
};
const signOut = async () => {
try {
await GoogleSignin.revokeAccess();
await GoogleSignin.signOut();
setUser(null);
} catch (e: any) {
setError(e.toString());
}
};
return (
<View style={styles.container}>
<Card>
<CardHeader>
<CardTitle>Welcome!</CardTitle>
<CardDescription>Please sign in with your Google account</CardDescription>
</CardHeader>
<CardContent>
{!!error && <Text style={styles.errorText}>Error: {error}</Text>}
{!user ? (
<GoogleSigninButton onPress={signIn} />
) : (
<>
<Avatar>
<AvatarImage source={{ uri: user.user.photo }} />
<AvatarFallback>{user.user.name[0]}</AvatarFallback>
</Avatar>
<Text style={styles.welcomeText}>Hello, {user.user.name}!</Text>
<Button onPress={signOut}>Sign Out</Button>
</>
)}
</CardContent>
<CardFooter>
<Text>Happy coding! 🎉</Text>
</CardFooter>
</Card>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
justifyContent: 'center',
backgroundColor: '#f0f0f0'
},
errorText: {
color: 'red',
marginBottom: 10
},
welcomeText: {
fontSize: 18,
marginVertical: 10
}
});
A few notes about the code:
- Replace
'YOUR_WEB_CLIENT_ID'
with the actual Web Client ID from your Firebase project configuration (found in yourgoogle-services.json
under theoauth_client
section). - The UI components (like
Card
,Avatar
,Button
, etc.) come from react-native-reusables library. Feel free to swap them out or style your own components as needed.
Building & Testing Your App
Now that your code is set, it's time to test it on your device:
-
Create Development Builds:
# For iOS eas build -p ios --profile development # For Android eas build -p android --profile development
-
Install and Run Your Build:
- iOS: Drag and drop the
.app
file into the iOS Simulator. - Android: Install the APK on your device or emulator.
- iOS: Drag and drop the
-
Start the Expo Development Server:
expo start --dev-client
Make sure your development server is active when testing the builds.
Troubleshooting Tips
-
SHA-1 Mismatch (Android):
If your authentication fails, verify that the generated SHA-1 certificate in your Expo EAS configuration matches the one in your Firebase Console.
-
iOS Simulator Issues:
Double-check that you're using the correct
GoogleService-Info.plist
and that your bundle identifier is consistent with what you registered in Firebase. -
Web Client ID Errors:
It's common to use the wrong client ID. Make sure you pick the one corresponding to a client with the correct
client_type
from your Firebase config. -
General Debugging:
If something isn't working as expected, use
console.log
or even better, breakpoints to pinpoint the issue.
Wrapping Up
And there you have it! You've successfully set up Google Authentication in your React Native app using Firebase and Expo. Not only have you made your app more robust, but you've also taken another step in becoming an even more awesome developer.
If you enjoyed this guide or have any questions, feel free to leave a comment or reach out. I'm always here to help out a fellow coder. Happy coding, and see you in the next tutorial!
Persisting Authentication State
To maintain the user's authentication state across app restarts, update your authentication screen to check for existing sessions:
export default function AuthScreen() {
const [user, setUser] = React.useState<SignInSuccessResponse | null>(null);
const [error, setError] = React.useState<string | null>(null);
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
// Initialize Google Sign-In
GoogleSignin.configure({
webClientId: 'YOUR_WEB_CLIENT_ID',
scopes: ['email']
});
// Check for existing sign-in
checkCurrentUser();
}, []);
const checkCurrentUser = async () => {
try {
const isSignedIn = await GoogleSignin.hasPlayServices();
if (isSignedIn) {
const currentUser = await GoogleSignin.signInSilently();
setUser(currentUser);
}
} catch (error) {
if (error instanceof Error) {
setError(error.message);
}
} finally {
setIsLoading(false);
}
};
// ... rest of your component code ...
}
Key points about persistence:
- Use
GoogleSignin.hasPlayServices()
to check if Google Play Services is available and the user was previously signed in - Use
GoogleSignin.signInSilently()
to restore the previous session without user interaction - Add a loading state to prevent UI flicker while checking authentication status
This approach will automatically restore the user's session when they reopen your app, providing a seamless experience.