Skip to main content

Setup Google sso in React Native Expo

Step 0: Prerequisites

Check for the node version, should be >=20.18.0

Step 1: Create new react native expo project

let's name it demo-app

npx create-expo-app@latest -y demo-app
cd demo-app

Step 2: Create pre build

npx expo prebuild --clean

Learn more https://docs.expo.dev/guides/adopting-prebuild/

Step 3: Install dependencies

npm i @react-native-firebase/app @react-native-firebase/auth @react-native-google-signin/google-signin expo-build-properties

Step 4: Create firebase project

https://console.firebase.google.com/

firebase-create-project

Step 5: Enable google authentication on firebase console

https://console.firebase.google.com/project/silent-shard/authentication

firebase-enable-auth

Enable google authentication on firebase console. firebase-enable-google

Continue to the next step. firebase-enable-google2

Step 6: iOS setup for google authentication.

Step 6.1: Get bundle id

You can get the bundle id from app.json in expo::ios::bundleIdentifier.

Step 6.2: Open project settings on firebase console.

firebase-project-settings

Step 6.3: Create ios app on firebase project settings,

firebase-ios-app

Step 6.4: Download the GoogleService-Info.plist and paste it in the root of the project.

firebase-ios-app-download

Continue and create the ios app on firebase project settings.

Step 6.5: Add googleServicesFile in app.json in

{
"expo": {
"ios": {
"googleServicesFile": "./GoogleService-Info.plist"
}
}
}

Step 7: Android setup for google authentication.

Step 7.1: Get package name

Get the package name from app.json in expo::android::package.

Step 7.2: Get the sha1 by running the following command in the root of the project.

cd android && ./gradlew signingReport

You will see the list of sha1, choose the one that has Store value as your project path.

Step 7.3: Open project settings.

firebase-project-settings

Step 7.4: Create android app on firebase project settings,

firebase-android-app

Step 7.5: Download the google-services.json and paste it in the root of the project.

firebase-android-app-download

Continue and create the android app on firebase project settings.

Step 7.6: Add googleServicesFile in app.json in

{
"expo": {
"android": {
"googleServicesFile": "./google-services.json"
}
}
}

Step 8: Add plugins in app.json

{
"expo": {
"plugins": [
"@react-native-firebase/app",
[
"expo-build-properties",
{
"ios": {
"useFrameworks": "static",
"deploymentTarget": "16.0"
}
}
],
]
}
}

Step 9: Create pre build again.

npx expo prebuild --clean

Learn more https://docs.expo.dev/guides/adopting-prebuild/

Step 10: Create services

Create a folder services in the root of the project where we will store the all code.

mkdir services

Step 11: Create FirebaseAuthService.ts

Create a file FirebaseAuthService.ts in the services folder.

Show FirebaseAuthService.ts code
import auth from '@react-native-firebase/auth';
import { GoogleSignin } from '@react-native-google-signin/google-signin';

export interface AuthUser {
uid: string;
email: string | null;
displayName: string | null;
photoURL: string | null;
}

export class FirebaseAuthService {
private static instance: FirebaseAuthService;

private constructor() {
this.configureGoogleSignIn();
}

public static getInstance(): FirebaseAuthService {
if (!FirebaseAuthService.instance) {
FirebaseAuthService.instance = new FirebaseAuthService();
}
return FirebaseAuthService.instance;
}

private configureGoogleSignIn() {
GoogleSignin.configure({
webClientId: '<your web client id>.apps.googleusercontent.com',
iosClientId: '<your ios client id>.apps.googleusercontent.com',
offlineAccess: true,
});
}

/**
* Sign in with Google and authenticate with Firebase
*/
public async signInWithGoogle(): Promise<AuthUser | null> {
try {
// Check if Google Play Services are available
await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });

// Sign in with Google first
await GoogleSignin.signIn();

// Get the tokens after successful sign in
const tokens = await GoogleSignin.getTokens();
const { idToken } = tokens;

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

// Sign-in the user with the credential
const userCredential = await auth().signInWithCredential(googleCredential);

const user = userCredential.user;
console.log('✅ Firebase Auth: Successfully signed in user:', user.email);

return {
uid: user.uid,
email: user.email,
displayName: user.displayName,
photoURL: user.photoURL,
};
} catch (error) {
console.error('❌ Firebase Auth: Sign in error:', error);
throw error;
}
}

/**
* Sign out the current user
*/
public async signOut(): Promise<void> {
try {
// Sign out from Google
await GoogleSignin.signOut();

// Sign out from Firebase
await auth().signOut();

console.log('✅ Firebase Auth: User signed out successfully');
} catch (error) {
console.error('❌ Firebase Auth: Sign out error:', error);
throw error;
}
}

/**
* Get the current Firebase user
*/
public getCurrentUser(): AuthUser | null {
const user = auth().currentUser;
if (!user) return null;

return {
uid: user.uid,
email: user.email,
displayName: user.displayName,
photoURL: user.photoURL,
};
}

/**
* Get the Firebase ID token for the current user
* This is what you need to send to your backend
*/
public async getFirebaseIdToken(): Promise<string | null> {
try {
const user = auth().currentUser;
if (!user) {
console.warn('🔒 Firebase Auth: No user signed in');
return null;
}

// Get the Firebase ID token (this is what your backend expects)
const idToken = await user.getIdToken();
console.log('🔑 Firebase Auth: Got Firebase ID token');
return idToken;
} catch (error) {
console.error('❌ Firebase Auth: Error getting ID token:', error);
return null;
}
}

/**
* Get a fresh Firebase ID token (force refresh)
*/
public async getFreshFirebaseIdToken(): Promise<string | null> {
try {
const user = auth().currentUser;
if (!user) {
console.warn('🔒 Firebase Auth: No user signed in');
return null;
}

// Force refresh to get a new token
const idToken = await user.getIdToken(true);
console.log('🔑 Firebase Auth: Got fresh Firebase ID token');
return idToken;
} catch (error) {
console.error('❌ Firebase Auth: Error getting fresh ID token:', error);
return null;
}
}

/**
* Check if user is currently signed in
*/
public isSignedIn(): boolean {
return auth().currentUser !== null;
}

/**
* Listen to authentication state changes
*/
public onAuthStateChanged(callback: (user: AuthUser | null) => void): () => void {
return auth().onAuthStateChanged((firebaseUser) => {
if (firebaseUser) {
const user: AuthUser = {
uid: firebaseUser.uid,
email: firebaseUser.email,
displayName: firebaseUser.displayName,
photoURL: firebaseUser.photoURL,
};
callback(user);
} else {
callback(null);
}
});
}
}

// Export a singleton instance
export const firebaseAuth = FirebaseAuthService.getInstance();

Step 12: Update webClientId and iosClientId

Update the webClientId and iosClientId in the onGoogleButtonPress.ts file.

  • You can get the web client id from google-services.json,
{
"client_id": "<your web client id>.apps.googleusercontent.com",
"client_type": 3
}
  • You can get the ios client id from GoogleService-Info.plist,
<dict>
<key>CLIENT_ID</key>
<string>Your ios client id</string>
</dict>

Step 13: Update app/(tabs)/index.tsx

index.tsx code
import { FirebaseAuthService } from "@/services/FirebaseAuthService";
import { Button, SafeAreaView } from "react-native";

export default function Index() {
return (
<SafeAreaView>
<Button
title="Sign in with Google"
onPress={async () => {
await FirebaseAuthService.getInstance().signInWithGoogle();
const idToken =
await FirebaseAuthService.getInstance().getFirebaseIdToken();
console.log("🚀 idToken:", idToken);
}}
/>
</SafeAreaView>
);
}

Step 14: Run the project

npx expo start

Run the project on ios and android, click Sign in with Google button and you will see the user details in the console.