React Native Nitro Google Sign-In
Agent skill (install first for coding agents)
npx skills add react-native-nitro-google-sign-in/google-signin -g -y
Docs: https://react-native-nitro-google-sign-in.github.io/docs/agents/skill
Package install
bun add react-native-nitro-google-signin react-native-nitro-modules
bundle exec pod install --project-directory="ios"
Requires RN ≥ 0.76. Not Expo Go — use expo-dev-client.
Rules
| Topic | Rule |
|---|---|
| API | GoogleOneTapSignIn from react-native-nitro-google-signin |
| Configure first | GoogleOneTapSignIn.configure({ webClientId }) before sign-in |
serverAuthCode |
Requires offlineAccess: true in configure() — otherwise always null. requestScopes() still returns accessToken for on-device APIs without offline access |
| Backend | Verify every idToken on server (sig, aud, iss, exp); validate JWT hd if using hostedDomain |
| iOS offline grant | Silent signIn() returns serverAuthCode: null — use createAccount() for initial code |
revokeAccess |
Android: by email/id. iOS: current session only (throws if id mismatch) |
getTokens |
After sign-in; throws SIGN_IN_REQUIRED if no session. iOS: call clearCachedAccessToken before retry after 401 |
getCurrentUser |
Sync; returns user + scopes or null. Check scopes before requestScopes for existing users |
| Flow order | checkPlayServices → signIn → createAccount → presentExplicitSignIn |
Android autoDetect |
Needs google-services.json + com.google.gms.google-services plugin |
| iOS | GoogleService-Info.plist + REVERSED_CLIENT_ID URL scheme |
| Expo | Plugin react-native-nitro-google-signin; expo prebuild after native config |
| After native changes | Rebuild app — Metro alone is insufficient |
Sign-in flow
import {
GoogleOneTapSignIn,
isNoSavedCredentialFoundResponse,
isSuccessResponse,
} from 'react-native-nitro-google-signin'
GoogleOneTapSignIn.configure({ webClientId: 'autoDetect' })
await GoogleOneTapSignIn.checkPlayServices()
let response = await GoogleOneTapSignIn.signIn()
if (isNoSavedCredentialFoundResponse(response)) {
response = await GoogleOneTapSignIn.createAccount()
}
if (isNoSavedCredentialFoundResponse(response)) {
response = await GoogleOneTapSignIn.presentExplicitSignIn()
}
if (isSuccessResponse(response)) {
const { user, idToken } = response.data
}
Platform quick pick
- Expo → plugin +
googleServicesFileinapp.config.js→ reference.md#expo - Bare Android → SHA-1 + optional Google Services plugin → reference.md#android
- Bare iOS → plist + URL scheme → reference.md#ios
Troubleshooting
| Symptom | Likely fix |
|---|---|
DEVELOPER_ERROR (Android) |
Wrong SHA-1 or package on OAuth client |
type: 'cancelled' after picking account (Android release/Play) |
Missing Play App Signing / release SHA-1 on Android OAuth client — troubleshooting |
default_web_client_id was not found |
Add google-services.json + Gradle plugin |
| iOS redirect fails | Fix REVERSED_CLIENT_ID URL scheme |
pod install / Expo prebuild — AppCheckCore / RecaptchaInterop (or conflict with Firebase App Check) |
Expo: upgrade package + prebuild --clean (plugin adds modular headers, no AppCheckCore < 11.3 pin). Bare: add AppCheckCore/GoogleUtilities/RecaptchaInterop with :modular_headers => true — troubleshooting |
| Nitro not found | Rebuild dev client / bundle exec pod install --project-directory="ios" |
| Android button laid out but blank | Upgrade package (in-process branding button) + rebuild native app |
| Sign-in OK in debug, fails in release | Consumer ProGuard rules ship with library; avoid -keep androidx.**; test assembleRelease. Also check release/Play SHA-1 (see cancelled-after-account-pick above) |
More detail
- reference.md — API, Expo/bare setup, errors
- examples.md — copy-paste snippets
- Docs: https://react-native-nitro-google-sign-in.github.io/