Modern Google Sign-In for React Native. A typed, cross-platform signIn() API backed by Android's Credential Manager and the GoogleSignIn-iOS SDK, plus a branding-compliant <GoogleSignInButton /> component and a first-party Expo config plugin. TypeScript-first, ships as a Turbo Module for the new architecture, and works in both bare React Native CLI projects and Expo dev-client / EAS Build.
Platform support: ✅ Android · ✅ iOS · ✅ Expo (dev-client / EAS Build)
⚠️ Early development. This package is pre-1.0 and under active development. The public API — configuration options, method signatures,GoogleSignInButtonprops, and error codes — may change between minor versions without a deprecation cycle. If you need stability, pin the exact version inpackage.json("@thoughtbot/react-native-social-auth": "0.x.y", not"^0.x.y") and check the CHANGELOG before upgrading. We aim for a stable1.0.0once the API has been battle-tested.
- Android Credential Manager and iOS GoogleSignIn-iOS SDK integration, both with auto-sign-in + interactive fallback
- Google-branding-compliant
GoogleSignInButton(3 themes, 2 shapes, 3 text variants, icon-only) - TypeScript-first, ships as a Turbo Module (new architecture)
- Typed errors via
GoogleSignInErrorandGoogleSignInErrorCodefor clean UX-level handling
- React Native
>=0.74with the new architecture enabled - Android
minSdkVersion24 - A Google Cloud project with OAuth 2.0 credentials (see setup)
react-native-svg>=13.0.0(peer dependency — used to render the Google "G" logo)
yarn add @thoughtbot/react-native-social-auth react-native-svg
# or
npm install @thoughtbot/react-native-social-auth react-native-svg
react-native-svgis a peer dependency. If it's not already in your app, install it explicitly — otherwise you'll see runtime errors likeTried to register two views with the same name RNSVGRect.
After installing, rebuild the native app:
# Android
yarn android
# iOS (when supported)
cd ios && pod install && cd ..
yarn iosMost "sign-in failed" issues come from misconfigured credentials. Follow these steps once per project.
- Create a project at console.cloud.google.com.
- Configure the OAuth consent screen:
- User type: External
- Publishing status: Testing is fine for development
- Add your Google account under Test users
- Create a Web application OAuth client ID under APIs & Services → Credentials. Copy the Client ID — this is the value you'll pass as
webClientId. - Create an Android OAuth client ID in the same project:
- Package name: your app's
applicationId(e.g.com.example.myapp) - SHA-1 certificate fingerprint: get it with
and copy the
cd android && ./gradlew signingReport
SHA1line underVariant: debug.
- Package name: your app's
- Repeat step 4 for production. The debug client only authorizes your debug-signed APK. Before shipping a signed release build (Play Store, internal testing tracks, or any release-signed APK), create a second Android OAuth client in the same GCP project using the same package name and the release SHA-1 of your upload/signing key. If you use Play App Signing, use the App signing key certificate SHA-1 from the Play Console (Setup → App integrity), not your upload key. Without this, production users will hit
[28444] Developer console is not set up correctly. - For iOS, also create an iOS OAuth client ID in the same GCP project with your app's Bundle Identifier. Copy the Client ID — pass it as
iosClientId. Copy the iOS URL scheme Google shows you (it's the reversed iOS Client ID, e.g.com.googleusercontent.apps.123456-abcdef) — you'll add it toInfo.plistin the next section.
The Web client ID is what your code references for the ID-token audience; each platform-specific client (Android debug, Android release, iOS) is an invisible passport that authorizes a specific build to use it. All clients must live in the same GCP project.
In addition to the Cloud Console step above, the host app needs two iOS-specific changes.
Using Expo? Skip the manual
Info.plistandAppDelegateedits below — our config plugin handles them duringexpo prebuild. Bare React Native CLI users continue with the manual steps in this section.
Google routes the sign-in callback back into your app via a custom URL scheme. Add the reversed iOS Client ID to Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.YOUR-REVERSED-IOS-CLIENT-ID</string>
</array>
</dict>
</array>If you use Expo, declare it in app.json under expo.ios.infoPlist.CFBundleURLTypes and rerun npx expo prebuild --platform ios --clean.
In your AppDelegate, forward application(_:open:options:) to GIDSignIn.sharedInstance.handle(_:). Importing GoogleSignIn here pulls in the official GoogleSignIn-iOS SDK module (already a transitive dependency of this package).
Swift:
import GoogleSignIn
@objc
public func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
return GIDSignIn.sharedInstance.handle(url)
}Objective-C:
#import <GoogleSignIn/GoogleSignIn.h>
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
return [[GIDSignIn sharedInstance] handleURL:url];
}Pass both the Web client ID (token audience) and iOS client ID (caller identity) to configure:
GoogleSignIn.configure({
webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com',
});Finally, run cd ios && pod install after installing the package.
This package ships an Expo config plugin so you don't have to hand-edit Info.plist or AppDelegate in Expo projects. Both React Native CLI and Expo projects are supported — pick the setup section that matches your project.
Heads up: Expo Go cannot ship third-party native modules. You must use a development build (via
expo-dev-clientand EAS Build) or the bare workflow.
npx expo install @thoughtbot/react-native-social-auth react-native-svgIn app.config.ts (or app.json):
export default {
expo: {
// ...
plugins: [
[
'@thoughtbot/react-native-social-auth',
{
iosClientId: process.env.EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID,
},
],
],
},
};| Prop | Type | Required for iOS | Description |
|---|---|---|---|
iosClientId |
string |
Yes | Your iOS OAuth Client ID (e.g. 123456-abc.apps.googleusercontent.com). The plugin reverses it and registers the URL scheme. |
Omit iosClientId if you only target Android — the plugin becomes a no-op on iOS and logs a warning.
npx expo prebuild --cleanThis runs the plugin, which writes the reversed iOS Client ID into Info.plist's CFBundleURLSchemes and adds the application(_:open:options:) URL forwarder to AppDelegate. Subsequent prebuilds are idempotent — the plugin won't re-inject if its marker is already present.
You still call GoogleSignIn.configure({ webClientId, iosClientId }) from JS at runtime (the plugin handles the native bits; it doesn't replace configure()).
import { useState } from 'react';
import {
GoogleSignIn,
GoogleSignInButton,
isGoogleSignInError,
type GoogleUser,
} from '@thoughtbot/react-native-social-auth';
GoogleSignIn.configure({
webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
});
export function SignInScreen() {
const [user, setUser] = useState<GoogleUser | null>(null);
const handleSignIn = async () => {
try {
const credential = await GoogleSignIn.signIn();
setUser(credential.user);
// Send credential.idToken to your backend for verification.
} catch (error) {
if (isGoogleSignInError(error)) {
console.warn(error.code, error.message);
}
}
};
return <GoogleSignInButton onPress={handleSignIn} />;
}All members are named exports from @thoughtbot/react-native-social-auth.
A singleton with the runtime sign-in API. You must call configure() once before any other method, or they'll throw GoogleSignInError with code NOT_CONFIGURED.
Stores credentials and options used by subsequent calls.
| Field | Type | Required | Description |
|---|---|---|---|
webClientId |
string |
Yes | The Web application OAuth Client ID. This is the audience of the issued ID token. |
iosClientId |
string |
No | iOS OAuth Client ID. |
offlineAccess |
boolean |
No | Request a server auth code in addition to the ID token. Default false. |
scopes |
string[] |
No | Additional OAuth scopes beyond the default profile/email. |
hostedDomain |
string |
No | Restrict sign-in to a Google Workspace domain. |
autoSelect |
boolean |
No | If true, returning users sign in silently when possible. Default false. |
nonce |
string |
No | A unique value bound into the ID token; recommended when verifying tokens on a backend. |
Launches the sign-in flow. On Android, this tries an auto sign-in first (silently re-uses a previously authorized account) and falls back to the bottom sheet when no authorized account is found.
Resolves to a GoogleAuthCredential:
| Field | Type | Description |
|---|---|---|
idToken |
string |
The Google ID token. Verify this on your backend. |
accessToken |
string | null |
OAuth access token (null when not requested). |
serverAuthCode |
string | null |
One-time code for backend exchange (requires offlineAccess: true). |
user |
GoogleUser |
The authenticated user's profile. |
Rejects with a GoogleSignInError.
Clears the local credential state. The user remains signed into Google itself.
Returns the in-memory authenticated user, or null if no one has signed in since app launch.
Revokes the app's access to the user's Google account.
Synchronous check for whether a user is currently signed in (in memory).
| Field | Type |
|---|---|
id |
string |
email |
string |
displayName |
string | null |
givenName |
string | null |
familyName |
string | null |
photoUrl |
string | null |
See signIn above.
A pre-built button that conforms to the official Google branding guidelines. The button renders the Google "G" via react-native-svg, so it stays crisp at any density without bundling raster assets.
| Prop | Type | Default | Description |
|---|---|---|---|
theme |
'light' | 'dark' | 'neutral' |
'light' |
Visual theme. Picks the right background, border, and text color. |
shape |
'rounded' | 'square' |
'rounded' |
Pill (borderRadius: 20) or square (borderRadius: 4). |
text |
'signin' | 'signup' | 'continue' |
'signin' |
One of the three call-to-actions Google permits. |
size |
'standard' | 'icon' |
'standard' |
Full-width button with text, or 40×40 icon-only. |
onPress |
() => void |
— | Tap handler — wire this to GoogleSignIn.signIn(). |
disabled |
boolean |
false |
Renders at 0.38 opacity and disables taps. |
style |
StyleProp<ViewStyle> |
— | Additional container styles (margin, alignment, etc.). |
testID |
string |
— | Testing identifier. |
Do not restyle the logo, text, or theme colors — Google's brand review will reject apps that do.
Every error from GoogleSignIn is a GoogleSignInError with a code from GoogleSignInErrorCode. Use isGoogleSignInError to narrow:
import {
GoogleSignIn,
isGoogleSignInError,
GoogleSignInErrorCode,
} from '@thoughtbot/react-native-social-auth';
try {
await GoogleSignIn.signIn();
} catch (error) {
if (isGoogleSignInError(error)) {
switch (error.code) {
case GoogleSignInErrorCode.SIGN_IN_CANCELLED:
// User dismissed the bottom sheet — no UI needed.
break;
case GoogleSignInErrorCode.NO_CREDENTIALS:
showAlert('No Google accounts on this device.');
break;
case GoogleSignInErrorCode.PLAY_SERVICES_NOT_AVAILABLE:
showAlert('Google Play Services is missing or out of date.');
break;
default:
showAlert(`Sign-in failed: ${error.message}`);
}
}
}| Code | Meaning |
|---|---|
SIGN_IN_CANCELLED |
The user dismissed the bottom sheet. Don't show an error. |
SIGN_IN_FAILED |
Generic failure from Credential Manager — the message has details. |
NO_CREDENTIALS |
No Google accounts on the device, or no authorized accounts when auto sign-in was tried. |
PLAY_SERVICES_NOT_AVAILABLE |
Device is missing Google Play Services (common on bare emulators). |
NETWORK_ERROR |
The device couldn't reach Google's auth servers. |
NOT_CONFIGURED |
A method was called before GoogleSignIn.configure(). |
A runnable example lives in /example. To try it:
yarn install
cp example/.env.example example/.env
# Edit example/.env and set EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID (and EXPO_PUBLIC_GOOGLE_IOS_CLIENT_ID for iOS)
yarn workspace @thoughtbot/react-native-social-auth-example start --clear
yarn workspace @thoughtbot/react-native-social-auth-example android
# or for iOS:
yarn workspace @thoughtbot/react-native-social-auth-example iosFor iOS, edit example/app.json and replace REPLACE_WITH_REVERSED_IOS_CLIENT_ID under expo.ios.infoPlist.CFBundleURLTypes with your reversed iOS Client ID, then run npx expo prebuild --platform ios --clean before the yarn ios command.
The example showcases every variant of GoogleSignInButton and exercises the full public API.
React Native Social Auth is Copyright © 2026 thoughtbot. It is free software, and may be redistributed under the terms specified in the LICENSE file.
React Native Social Auth is maintained by thoughtbot, inc. The names and logos for thoughtbot are trademarks of thoughtbot, inc.
We love open source software! See our other projects or hire us to design, develop, and grow your product.