Google Sign-In for React Native: The Complete Setup Guide That Actually Works

Google Sign-In should be straightforward. You add a library, configure an OAuth client, and you’re done. Except you’re not. Between Firebase, Google Cloud Console, SHA-1 fingerprints, and platform-specific quirks, the setup process is scattered across multiple dashboards that never quite agree with each other.

I recently integrated Google Sign-In into a React Native app using Expo and @react-native-google-signin/google-signin. It worked perfectly in development. Then I deployed to the Google Play Store, and it silently broke. No error, no crash — just a Google account picker that led nowhere.

This guide covers every step from zero to production, including the one configuration detail that Google’s own documentation barely mentions.

What You Need Before Starting

Before writing any code, you’ll need:

  • A React Native project (Expo with development build or bare workflow)
  • A Firebase project (free tier is fine)
  • Access to the Google Cloud Console
  • For Android production: a Google Play Console account

This guide uses @react-native-google-signin/google-signin, which is the most widely adopted library for Google authentication in React Native. At the time of writing, I’m using version 16.x.

Step 1: Create a Firebase Project and Register Your Apps

Head to the Firebase Console and create a new project (or use an existing one).

Register both your iOS and Android apps:

  • Android: Use your exact package name (e.g., com.yourcompany.yourapp)
  • iOS: Use your bundle identifier (e.g., com.yourcompany.yourapp)

For Android, Firebase will ask for a SHA-1 fingerprint. For now, add your debug keystore fingerprint:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android

Copy the SHA1: value and paste it into Firebase. We’ll come back to add more fingerprints later — this is where most production issues originate.

Download both configuration files:

  • google-services.json for Android
  • GoogleService-Info.plist for iOS

Place them at the root of your project.

Step 2: Identify Your OAuth Client IDs

This is where confusion starts. Firebase automatically creates OAuth clients in Google Cloud Console behind the scenes. You need to understand which one does what.

Go to Google Cloud Console and select your Firebase project. Under OAuth 2.0 Client IDs, you’ll see several entries:

  • Web client (auto-created by Firebase) — this is the one you’ll use in your React Native code as `webClientId`
  • Android client — tied to your package name + SHA-1 fingerprint
  • iOS client — tied to your bundle ID

The web client ID is what you pass to the library configuration. The Android and iOS clients are used behind the scenes by Google’s SDK to validate that the request comes from a legitimate app. You never reference them directly in code, but they must exist.

Step 3: Install and Configure the Library

Install the package:

yarn add @react-native-google-signin/google-signin

If you’re using Expo, add the config plugin in your app.config.ts or app.json:

plugins: [
  [
    "@react-native-google-signin/google-signin",
    {
      iosUrlScheme:   "com.googleusercontent.apps.YOUR_IOS_CLIENT_ID",
    },
  ],
],

Also point Expo to your Firebase configuration files:

android: {
  googleServicesFile: "./google-services.json",
  package: "com.yourcompany.yourapp",
},
ios: {
  googleServicesFile: "./GoogleService-Info.plist",
  bundleIdentifier: "com.yourcompany.yourapp",
},

Then run npx expo prebuild to regenerate the native projects.

Step 4: Initialize Google Sign-In in Your App

Configure the library early in your app’s lifecycle — typically in your root App.tsx:

import { GoogleSignin } from "@react-native-google-signin/google-signin";

GoogleSignin.configure({
  webClientId: process.env["EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID"],
  iosClientId: process.env["EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID"],
  offlineAccess: true,
});

A few notes:

  • webClientId is required for both platforms. This is the web OAuth client ID from your Google Cloud Console, not an Android or iOS client.
  • iosClientId is only needed on iOS. Android ignores it.
  • offlineAccess: true gives you a server auth code that your backend can exchange for a refresh token, if you need server-side access.

Step 5: Implement the Sign-In Flow

Here’s a clean implementation:

import {
  GoogleSignin,
  isErrorWithCode,
  statusCodes,
} from "@react-native-google-signin/google-signin";

const handleGoogleSignIn = async () => {
  try {
    await GoogleSignin.hasPlayServices();
    const response = await GoogleSignin.signIn();
    if (response.data?.idToken) {
      // Send this token to your backend for verification
      await loginWithGoogle({ token: response.data.idToken });
    }
  } catch (error) {
    if (isErrorWithCode(error)) {
      switch (error.code) {
        case statusCodes.SIGN_IN_CANCELLED:
          // User closed the modal
          break;
        case statusCodes.IN_PROGRESS:
          // Sign-in already in progress
          break;
        case statusCodes.PLAY_SERVICES_NOT_AVAILABLE:
          // Android-only: Google Play Services missing or outdated
          break;
        default:
          // Unexpected error
          console.error(error);
      }
    }
  }
};

One thing I always do: call GoogleSignin.signOut() before signIn() if you want the account picker to show every time. Otherwise, the SDK may silently reuse the last selected account.

Step 6: iOS-Specific Configuration

For iOS, the setup is relatively painless. The GoogleService-Info.plist handles most of the heavy lifting.

Make sure you’ve added the reversed client ID as a URL scheme. If you’re using the Expo config plugin, this is handled automatically. If you’re in a bare workflow, add it to your Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>com.googleusercontent.apps.YOUR_IOS_CLIENT_ID</string>
    </array>
  </dict>
</array>

That’s it for iOS. No SHA-1 drama, no signing key headaches. iOS uses the bundle identifier for validation, which is consistent across debug and release builds.

The Android Production Trap: SHA-1 Fingerprints and Play App Signing

This is the section I wish I’d read before deploying.

Google Sign-In works in your Android emulator but silently fails on Google Play Store builds. The account picker opens, you select an account, and then… nothing. No error. No callback. Just silence.

Here’s why.

How Android Validates Your App

When your app calls Google Sign-In, Google’s SDK sends your app’s package name and SHA-1 signing certificate fingerprint to Google’s servers. Google checks these against the Android OAuth clients registered in your Cloud Console project. If there’s no match, the sign-in silently fails after account selection.

The Problem with Play App Signing

When you upload an AAB (Android App Bundle) to Google Play, Google re-signs your app with their own key before distributing it. This is called Play App Signing, and it’s mandatory for new apps.

This means your production app has a different SHA-1 fingerprint than:

  • Your debug keystore (used in the emulator)
  • Your upload keystore (used to sign the AAB before uploading)

You now have three possible signing keys, and Google Play users get the one you never explicitly created.

The Fix

1. Open the Google Play Console

2. Go to your app, then Setup > App signing

3. Find the App signing key certificate (not the upload key) and copy its SHA-1 fingerprint

4. Go to Firebase Console > your project > Project Settings > your Android app

5. Click Add fingerprint and paste the SHA-1

Firebase will automatically create the corresponding Android OAuth client in your Google Cloud project. You don’t need to change any code or download a new google-services.json. The validation happens server-side.

Add All Three Fingerprints

For complete coverage, register all three SHA-1 fingerprints in Firebase:

KeyWhere it’s usedHow to get it
Debug keystoreLocal emulatorkeytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android
Upload keystoreCI/CD build signingkeytool -list -v -keystore your-upload-keystore.jks -alias your-alias
App signing keyGoogle Play distributionGoogle Play Console > Setup > App signing

Miss any of these, and Google Sign-In breaks silently for that build type. No error message. No crash. Just a modal that goes nowhere.

Backend Token Verification

The idToken you receive from the sign-in response should be sent to your backend for server-side verification. Never trust the client-side token alone. Your backend should verify it using Google’s token verification endpoint or a Google client library:

// Node.js example using google-auth-library

const { OAuth2Client } = require("google-auth-library");
const client = new OAuth2Client(WEB_CLIENT_ID);

async function verifyGoogleToken(idToken) {
  const ticket = await client.verifyIdToken({
    idToken,
    audience: WEB_CLIENT_ID,
  });

  const payload = ticket.getPayload();
  // payload.sub is the unique Google user ID
  // payload.email is the user's email
  return payload;
}

Notice the audience matches your webClientId. This ensures the token was issued specifically for your app.

Debugging Google Sign-In Issues

When things go wrong, the silent failures make debugging painful. Here’s a checklist:

Sign-in modal opens but nothing happens after selecting an account:

  • Missing SHA-1 fingerprint for your build type (see section above)
  • Wrong package name in Firebase

Error: DEVELOPER_ERROR:

  • webClientId doesn’t match the web OAuth client in your Google Cloud project
  • SHA-1 fingerprint mismatch

Error: PLAY_SERVICES_NOT_AVAILABLE:

  • Testing on an emulator without Google Play Services (use a Google APIs system image)

Sign-in works but backend rejects the token:

  • Backend is verifying against a different audience than your webClientId
  • Token has expired (they’re short-lived)

iOS: sign-in button does nothing:

  • Missing URL scheme for the reversed iOS client ID
  • GoogleService-Info.plist not properly linked in the Xcode project

Conclusion

The actual code for Google Sign-In is about 30 lines. The real complexity is in the configuration — three dashboards, multiple OAuth clients, and SHA-1 fingerprints that differ across build environments.

The single most common production issue is the missing Play App Signing SHA-1 fingerprint. Google re-signs your app, the new fingerprint isn’t registered, and sign-in fails silently. Register all three fingerprints in Firebase and you’ll save yourself an evening of debugging.

If you take one thing from this guide: set up your production signing certificates before your first Play Store release, not after users start reporting that login is broken.


Discover more from The Dev World – Sergio Lema

Subscribe to get the latest posts sent to your email.


Comments

Leave a comment