Skip to main content

Troubleshooting

webClientId is "autoDetect" but default_web_client_id was not found (Android)

  • Add google-services.json to android/app/
  • Apply Google Services Gradle plugin (Android setup)
  • Ensure JSON package_name matches your applicationId
  • On Expo: set expo.android.googleServicesFile and re-run prebuild --clean

Android default_web_client_id was not found

You use webClientId: 'autoDetect' but Gradle did not generate the string resource:

  1. Add google-services.json under android/app/ with matching package_name.
  2. Add Google Services Gradle plugin (root classpath + app apply plugin).
  3. Rebuild the app (not just reload Metro).

Or pass an explicit Web client ID instead of 'autoDetect'.

iOS sign-in stuck after browser / OAuth redirect

Interactive sign-in opens a browser or account sheet, then should return to your app. If it hangs:

  1. Confirm URL scheme = REVERSED_CLIENT_ID from plist (iOS setup).
  2. On bare React Native, add GIDSignIn.sharedInstance.handle(url) in AppDelegate (details).
  3. If you use Facebook or other openURL handlers, chain them with || before/after Google's handler.

iOS URL scheme / redirect errors (App crash on button tap)

If the app crashes immediately upon tapping the Google Sign-In button with a stack trace in HybridNitroGoogleSignin.signIn or an NSInvalidArgumentException stating Your app is missing support for the following URL schemes: com.googleusercontent.apps.XXXX, the custom URL scheme is missing:

  • Required for both Simulators and Real Devices: This is a mandatory step for all environments because iOS needs the custom scheme to route the browser redirect back into your app.
  • Add the REVERSED_CLIENT_ID (e.g. com.googleusercontent.apps.XXXX) as a URL scheme in Info.plist (under CFBundleURLTypes) or in Xcode -> Targets -> Info -> URL Types.
  • Expo: include GoogleService-Info.plist or iosUrlScheme in the plugin configuration.
  • Re-run prebuild (npx expo prebuild --clean) and compile the app again after changing the URL schemes.

iOS pod install fails — AppCheckCore / RecaptchaInterop (Expo 56+)

pod install or expo prebuild may fail with:

The Swift pod `AppCheckCore` depends upon `GoogleUtilities` and `RecaptchaInterop`,
which do not define modules. To opt into those targets generating module maps...

This happens when CocoaPods resolves AppCheckCore ≥ 11.3 (from Google Sign-In 9.2+ and/or @react-native-firebase/app-check) under Expo’s default static pod setup.

A related failure with Firebase App Check looks like:

CocoaPods could not find compatible versions for pod "AppCheckCore":
AppCheckCore (< 11.3.0)
AppCheckCore (~> 11.3)

Do not pin AppCheckCore below 11.3.0 — that conflicts with Firebase App Check. Use modular headers instead (below).

Why not NitroGoogleSignin.podspec?

CocoaPods does not let a podspec enable :modular_headers => true on dependencies — that option exists only in the app Podfile (or via a config plugin that edits it).

We also cannot add AppCheckCore as a direct s.dependency in the podspec: NitroGoogleSignin is a Swift pod, and CocoaPods then reports that AppCheckCore does not define modules (same class of error).

So the library handles this in two places:

App typeWho patches the Podfile
Exporeact-native-nitro-google-signin config plugin (automatic on expo prebuild)
Bare RNYou add the pods below to ios/Podfile

Expo (dev client)

The config plugin patches ios/Podfile during prebuild (modular headers for AppCheckCore, GoogleUtilities, and RecaptchaInteropno AppCheckCore version pin). Ensure the plugin is listed in app.config.js, upgrade react-native-nitro-google-signin, then regenerate native projects:

npx expo prebuild --clean

No manual Podfile edits are needed for Expo.

Bare React Native

Add the following inside your app target block in ios/Podfile, before use_native_modules!:

# react-native-nitro-google-signin: AppCheckCore ≥ 11.3 + static CocoaPods needs modular headers.
pod 'AppCheckCore', :modular_headers => true
pod 'GoogleUtilities', :modular_headers => true
pod 'RecaptchaInterop', :modular_headers => true

Then reinstall pods from your app root:

bundle exec pod install --project-directory="ios"

See also Expo setup and iOS setup.

Release builds / R8 / ProGuard

Sign-in works in debug but crashes or no-ops in release after enabling minifyEnabled true:

  1. Consumer rulesreact-native-nitro-google-signin ships consumer-rules.pro with the AAR. Upgrade the package instead of copying keeps manually (Android setup — ProGuard / R8).
  2. Do not add blanket -keep class androidx.** { *; } for Credential Manager — androidx.credentials and credentials-play-services-auth already embed the rules they need.
  3. Peer — install and rebuild with react-native-nitro-modules (Nitro JNI).
  4. Verify — reproduce on assembleRelease or your store build, then inspect logcat for ClassNotFoundException / missing HybridNitroGoogleSignin.

DEVELOPER_ERROR / sign-in fails immediately (Android)

  • Wrong SHA-1 (or missing SHA-256 in Firebase) on the Android OAuth client
  • Package name mismatch
  • Android OAuth client ID passed to configure() instead of the Web client ID — Credential Manager setServerClientId must use the Web client (*.apps.googleusercontent.com)
  • Web client ID from a different Google Cloud project than the Android client

See Android — Credential Manager checklist.

type: 'cancelled' after picking a Google account (Android production)

Credential Manager often reports OAuth misconfiguration as user cancellation, not DEVELOPER_ERROR.

Symptom: Account picker / Sign in with Google UI appears → user selects an account → JS receives type: 'cancelled' (not a thrown error). Works in debug, fails on release / Play Store builds.

Cause: Google validates the app’s signing certificate against the Android OAuth client. Debug builds use the debug keystore SHA-1; Play builds use the Play App Signing certificate (different from your upload keystore). If that SHA-1 is missing, Play services closes the flow with RESULT_CANCELED, which this library maps to type: 'cancelled'.

Fix:

  1. Open Play Console → App integrity → App signing and copy the App signing key certificate SHA-1 (and SHA-256 if you use Firebase).
  2. Also register your upload key SHA-1 if you test local assembleRelease / sideloaded release APKs.
  3. Add those fingerprints to the Android OAuth client (same package name as applicationId) in Google Cloud Console and/or Firebase Project settings.
  4. Confirm configure({ webClientId }) uses the Web client ID from the same Google Cloud project — never the Android client ID.
  5. Rebuild and reinstall the production/release binary (Metro reload is not enough). Changes to OAuth clients can take a few minutes to propagate.

Logcat will include a GoogleSignInController warning when Credential Manager returns cancellation, pointing at SHA-1 checks.

See Android SHA-1 and DEVELOPER_ERROR.

Nitro / TurboModule not found

  • Rebuild native app after installing the package
  • Expo: create a new dev client (expo prebuild --clean + expo run:ios|android)
  • Confirm react-native-nitro-modules is installed

Expo config plugin errors

Missing iosUrlScheme:

Configure either Firebase files or manual scheme:

["react-native-nitro-google-signin", { "iosUrlScheme": "com.googleusercontent.apps...." }]

Play Services (Android)

Call checkPlayServices() and use an emulator image with Google Play.

Platform-specific behavior

Platform differences for signOut(), revokeAccess(), hostedDomain, and scope requests are documented in Usage and the API reference.

Google Workspace: hostedDomain rejected on button flow (Android)

When hostedDomain is configured and you use presentExplicitSignIn() or GoogleSignInButton with signInBehavior="buttonFlow", sign-in fails if the signed-in account's JWT hd claim does not match the configured domain (for example a consumer @gmail.com account when you require corp.example.com).

Credential Manager flows (signIn, createAccount, signInBehavior="credentialManager") apply the domain filter during the request.

Always validate hd on your backend — client-side checks are not sufficient on their own.

iOS: revokeAccess throws "does not match the current signed-in user"

On iOS, revokeAccess(emailOrUniqueId) only disconnects the active session. If you pass an email or id that is not the currently signed-in user, the call throws.

Call signIn() (or ensure the target account is the current user) before revokeAccess(), or use signOut() for a local session clear.

iOS: Missing serverAuthCode on silent signIn() with offlineAccess: true

Even when offlineAccess: true is set, iOS silent signIn() and restorePreviousSignIn() return serverAuthCode: null. This is expected — Google only issues a server auth code during an interactive authorization flow.

Use createAccount() or presentExplicitSignIn() for the initial offline grant.

Android: Sign-in hangs after enabling offlineAccess: true

If sign-in (imperative API or useGoogleSignInFromButton) appears to hang after you add offlineAccess: true to configure(), update to a release that no longer forces AuthorizationRequest.Prompt.CONSENT on every offline authorization. Forcing consent immediately after Credential Manager could leave the PendingIntent unresolved.

Also ensure:

  1. You rebuild the native app after upgrading the library (Metro reload is not enough).
  2. The Web client ID in configure({ webClientId }) is correct (not the Android client ID).
  3. Debug/release/Play App Signing SHA-1 fingerprints are registered on the Android OAuth client.

serverAuthCode is always null unless configure({ offlineAccess: true }). That is expected when you only need on-device API access.

Use the accessToken field from requestScopes() to call Google APIs (Drive, Calendar, etc.):

const { accessToken, serverAuthCode } = await GoogleOneTapSignIn.requestScopes([
'https://www.googleapis.com/auth/drive.file',
])
// accessToken — call Google APIs from the device
// serverAuthCode — only non-null when offlineAccess: true

If consent still does not appear for a new scope:

  1. Confirm the user signed in successfully first (imperative or hook).
  2. Add the scope on the OAuth consent screen and enable the related Google API.
  3. Rebuild the native app after upgrading this library.

iOS: Missing serverAuthCode when scopes are already granted

On iOS, when calling requestScopes() or signIn() with scopes that the user has already approved in the past, the native iOS SDK returns a local error scopesAlreadyGranted (-8) and does not contact Google's authorization servers. As a result, no new one-time serverAuthCode is issued.

How to resolve:

  • Force re-authorization via presentExplicitSignIn(): Configure the library without the specific scopes (or with only basic scopes) and call presentExplicitSignIn(). This forces the account chooser browser sheet to display. Since Google OAuth supports incremental/cumulative consent, when your backend exchanges this fresh serverAuthCode for a refresh token, Google will issue a token containing all scopes the user has previously authorized.
  • Or call signOut() first: Calling signOut() resets the SDK's local keychain state, forcing the next sign-in flow to contact Google's servers and request a fresh serverAuthCode.

getTokens() returns the same access token on iOS

On iOS, getTokens() returns the current in-memory access token while it is still valid. Google only issues a new access token when the current one is expired or marked for refresh.

Expected: Two consecutive getTokens() calls without clearing may return the same access token string.

To force a refresh (for example after a Google API returns 401):

  1. Call clearCachedAccessToken(accessToken) with the token that failed.
  2. Call getTokens() again — iOS performs a network refresh via AppAuth.

On Android, clearCachedAccessToken() removes the token from AuthorizationClient's local cache; the next getTokens() requests a new one from Google.

See Usage — Access tokens.

Android: GoogleSignInButton is laid out but invisible

On some Android 15+/Play services combinations the old GMS SignInButton Dynamite remote view could measure at the correct size and still paint nothing.

This library draws the Android button in-process with Play services branding assets. Upgrade react-native-nitro-google-signin and rebuild the native app (Metro reload is not enough).

If the button collapses to 0×0 under the New Architecture without an explicit style, ensure you are on a release that applies intrinsic size from the size prop (or set style yourself using GOOGLE_SIGN_IN_BUTTON_HEIGHT / GOOGLE_SIGN_IN_BUTTON_WIDTH).

Still stuck?

Open an issue with platform, RN version, Expo vs bare, and whether you use autoDetect or an explicit webClientId:

GitHub Issues