essential-google-signin
v0.3.0
Published
Native Google Sign-In for Expo using Android Credential Manager and iOS GoogleSignIn SDK
Maintainers
Readme
essential-google-signin
Native Google Sign-In for Expo using Android Credential Manager and iOS GoogleSignIn SDK.
This package provides a simple, modern implementation of Google authentication for React Native apps built with Expo. It uses the latest Android Credential Manager API and the official Google Sign-In SDK for iOS.
Features
- ✅ Native Google Sign-In for Android and iOS
- ✅ Uses Android Credential Manager (modern, recommended approach)
- ✅ Uses GoogleSignIn SDK for iOS
- ✅ Automatic configuration via Expo config plugin
- ✅ ID token verification on Android
- ✅ TypeScript support
- ✅ Sign out functionality
- ⚠️ Web platform not supported (native SDKs only)
Platform Support
| Platform | Supported | Implementation | | -------- | --------- | ---------------------- | | iOS | ✅ Yes | GoogleSignIn SDK | | Android | ✅ Yes | Credential Manager API | | Web | ❌ No | Native only |
Installation
npm install essential-google-signinor
yarn add essential-google-signinPrerequisites
Before using this library, you need to set up Google Sign-In credentials in the Google Cloud Console:
1. Create a Google Cloud Project
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the Google+ API (or Google Identity Services)
2. Create OAuth 2.0 Credentials
You'll need to create three different OAuth 2.0 client IDs (all three are required):
Android Client ID
- In Google Cloud Console, go to APIs & Services > Credentials
- Click Create Credentials > OAuth 2.0 Client ID
- Select Android as application type
- Enter your package name (e.g.,
com.yourcompany.yourapp) - Get your SHA-1 certificate fingerprint:
# For debug builds cd android ./gradlew signingReport # Look for SHA1 under "Variant: debug" - Save the Client ID (format:
xxx-xxx.apps.googleusercontent.com)
iOS Client ID
- Create another OAuth 2.0 Client ID
- Select iOS as application type
- Enter your iOS bundle identifier (e.g.,
com.yourcompany.yourapp) - Save the Client ID (format:
xxx-xxx.apps.googleusercontent.com)
Web Client ID - Required
⚠️ Important: Despite the name, the "Web Client ID" is required for Android and backend token verification. It's not related to web platform support.
- Create one more OAuth 2.0 Client ID
- Select Web application as application type
- Save the Client ID (format:
xxx-xxx.apps.googleusercontent.com)
Why it's needed:
- Android Credential Manager requires a web client ID to generate OAuth tokens
- Backend servers use this to verify ID tokens
- It's a requirement of Google's OAuth flow, not for web platform support
Configuration
Add the plugin to your app.json:
{
"expo": {
"plugins": [
[
"essential-google-signin",
{
"androidClientId": "YOUR_ANDROID_CLIENT_ID.apps.googleusercontent.com",
"iosClientId": "YOUR_IOS_CLIENT_ID.apps.googleusercontent.com",
"webClientId": "YOUR_WEB_CLIENT_ID.apps.googleusercontent.com"
}
]
]
}
}Run prebuild
After adding the plugin, run prebuild to apply the configuration:
npx expo prebuildThis will:
- Add the client IDs to
AndroidManifest.xml(Android) - Add the client ID and URL scheme to
Info.plist(iOS) - Configure iOS AppDelegate for OAuth callbacks
- Set up Google Sign-In session restoration
Usage
Basic Example
import EssentialGoogleSignin from 'essential-google-signin';
import { useEffect, useState } from 'react';
import { Button, Platform, Text, View } from 'react-native';
export default function App() {
const [user, setUser] = useState(null);
useEffect(() => {
// Skip on web (native only)
if (Platform.OS === 'web') return;
// Configure on app start
EssentialGoogleSignin.configure()
.then(config => console.log('Configured:', config))
.catch(error => console.error('Configuration error:', error));
}, []);
const handleSignIn = async () => {
try {
const result = await EssentialGoogleSignin.signIn();
console.log('Sign in successful:', result);
setUser(result.data);
} catch (error) {
console.error('Sign in error:', error);
}
};
const handleSignOut = async () => {
try {
await EssentialGoogleSignin.signOut();
setUser(null);
console.log('Signed out');
} catch (error) {
console.error('Sign out error:', error);
}
};
return (
<View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
{user ? (
<>
<Text>Welcome, {user.name}!</Text>
<Text>Email: {user.email}</Text>
<Button title="Sign Out" onPress={handleSignOut} />
</>
) : (
<Button title="Sign In with Google" onPress={handleSignIn} />
)}
</View>
);
}Android account selection behavior
You can control whether Android should try auto-selecting an account when possible:
await EssentialGoogleSignin.configure({
androidAutoSelectEnabled: true, // default
});true(default): allows automatic account selection when Google Credential Manager determines it is safe/eligible.false: forces explicit account selection UI.
Note: This option is Android-only. iOS ignores it.
Native Google Sign-In Button
This package also exports a native GoogleSigninButton component (similar to @react-native-google-signin/google-signin).
import EssentialGoogleSignin, {
GoogleSigninButton,
} from "essential-google-signin";
import { useEffect } from "react";
import { Platform, View } from "react-native";
export default function App() {
useEffect(() => {
if (Platform.OS === "web") return;
EssentialGoogleSignin.configure();
}, []);
return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<GoogleSigninButton
size={GoogleSigninButton.Size.Wide}
color={GoogleSigninButton.Color.Dark}
onPress={() => EssentialGoogleSignin.signIn()}
disabled={Platform.OS === "web"}
/>
</View>
);
}Button props
size:GoogleSigninButton.Size.Standard(230x48),Wide(312x48),Icon(48x48)color:GoogleSigninButton.Color.LightorGoogleSigninButton.Color.Darkdisabled: disables interaction whentrueonPress: callback invoked when the native button is tapped
Note: This button is native-only (iOS/Android). It renders nothing useful on web.
API Reference
Methods
configure(options?: ConfigureOptions): Promise<ConfigureResult>
Configures Google Sign-In by reading client IDs from native configuration.
Options:
{
androidAutoSelectEnabled?: boolean; // Android only, default true
}Returns:
{
webClientId?: string; // Web client ID (Android always, iOS optional)
androidClientId?: string; // Android only
iosClientId?: string; // iOS only
}Throws:
CONFIG_ERROR- If client IDs are not found in native configuration
Note: You must call this before signIn().
signIn(): Promise<GoogleSignInResult>
Initiates the Google Sign-In flow and returns user data.
Returns:
{
success: true;
data: {
id: string; // Google user ID
email: string; // User's email
emailVerified: boolean; // Email verification status
name: string; // Full name
givenName: string; // First name
familyName: string; // Last name
pictureUrl: string; // Profile picture URL
locale?: string; // User's locale (Android only)
idToken: string; // JWT ID token for backend verification
}
}Throws:
CONFIG_ERROR- Ifconfigure()hasn't been calledSIGN_IN_ERROR- If sign-in fails or user cancelsTOKEN_ERROR- If token verification fails (Android)CREDENTIAL_ERROR- If credential type is unexpected
signOut(): Promise<void>
Signs out the current user.
Returns: Promise<void>
hasPlayServices(): Promise<boolean>
Checks if Google Play Services is available (Android only).
Returns:
trueif Google Play Services is available (Android) or alwaystrueon iOSfalseif Google Play Services is not available (Android only)
Note: On iOS, this always returns true as it doesn't require Play Services.
Types
type GoogleUserData = {
id: string;
email: string;
emailVerified: boolean;
name: string;
pictureUrl: string;
locale?: string;
familyName: string;
givenName: string;
idToken: string;
};
type GoogleSignInResult = {
success: true;
data: GoogleUserData;
};
type ConfigureResult = {
webClientId: string;
androidClientId?: string;
iosClientId?: string;
};
type ConfigureOptions = {
androidAutoSelectEnabled?: boolean;
};Platform-Specific Behavior
Android
- Uses Credential Manager API (modern replacement for deprecated GoogleSignInClient)
- Verifies ID tokens server-side using Google's verification library
- Requires Google Play Services to be installed
- Supports Android 7.0 (API 24) and above
- Uses SHA-256 nonce for enhanced security
iOS
- Uses GoogleSignIn SDK (official library from Google)
- Handles OAuth callback URLs automatically via AppDelegate
- Restores previous sign-in state on app launch
- Supports iOS 14.0 and above
Troubleshooting
Android: "Cannot find a matching credential"
This error typically means the SHA-1 fingerprint in Google Cloud Console doesn't match your app's signing certificate.
Solution:
- Get your SHA-1 fingerprint:
cd android && ./gradlew signingReport - Add it to your OAuth 2.0 Client ID in Google Cloud Console
- Make sure you're using the correct package name
Android: "BAD_AUTHENTICATION" or "Long live credential not available"
This error means the web client ID is incorrect or the OAuth configuration is wrong.
Solution:
- Verify the
webClientIdin yourapp.jsonmatches the Web Client ID from Google Cloud Console (not Android or iOS) - Ensure you've added the SHA-1 fingerprint for your signing certificate
- Run
npx expo prebuild --cleanafter changing the config
iOS: "Your app is missing support for the following URL schemes"
This means the URL scheme isn't properly configured in Info.plist.
Solution:
- Run
npx expo prebuild --cleanto regenerate native projects - Verify the URL scheme in Info.plist matches:
com.googleusercontent.apps.{YOUR_IOS_CLIENT_ID_PREFIX} - The config plugin should handle this automatically
"Google Sign-In is not configured. Call configure() first."
Solution:
- Make sure you call
configure()beforesignIn() - Ensure your client IDs are properly set in
app.json - Verify that
npx expo prebuildwas run after adding the plugin
iOS: App crashes on launch after adding the module
Solution:
- Make sure GoogleSignIn pod is properly installed:
cd ios && pod install - Clean build:
npx expo run:ios --clean
Web: Module doesn't load or useEffect doesn't run
This module only works on native platforms (iOS and Android). Web is not supported because it uses platform-specific native SDKs.
Solution:
Use platform detection to skip on web:
import { Platform } from "react-native";
useEffect(() => {
if (Platform.OS === "web") {
console.log("Google Sign-In not available on web");
return;
}
// Your Google Sign-In code here
}, []);For web support, you'd need to integrate Google's JavaScript SDK separately.
Backend Verification
The ID token returned from signIn() should be verified on your backend server for security:
Node.js Example
const { OAuth2Client } = require("google-auth-library");
const client = new OAuth2Client(YOUR_WEB_CLIENT_ID);
async function verifyToken(idToken) {
try {
const ticket = await client.verifyIdToken({
idToken: idToken,
audience: YOUR_WEB_CLIENT_ID,
});
const payload = ticket.getPayload();
const userId = payload["sub"];
// You can now trust these values:
// - payload.email
// - payload.name
// - payload.picture
return {
userId,
email: payload.email,
name: payload.name,
picture: payload.picture,
};
} catch (error) {
console.error("Token verification failed:", error);
throw new Error("Invalid token");
}
}Python Example
from google.oauth2 import id_token
from google.auth.transport import requests
def verify_token(token):
try:
idinfo = id_token.verify_oauth2_token(
token,
requests.Request(),
YOUR_WEB_CLIENT_ID
)
user_id = idinfo['sub']
email = idinfo['email']
name = idinfo['name']
return {
'user_id': user_id,
'email': email,
'name': name
}
except ValueError:
raise Exception('Invalid token')Development
To work on this module locally:
# Install dependencies
npm install
# Build the module
npm run build
# Run example app
cd example
npx expo prebuild
npx expo run:android
npx expo run:iosProject Structure
essential-google-signin/
├── android/ # Android native module
│ ├── build.gradle # Android dependencies
│ └── src/main/java/ # Kotlin source files
├── ios/ # iOS native module
│ ├── *.swift # Swift source files
│ └── *.podspec # CocoaPods spec
├── src/ # TypeScript/JavaScript source
│ ├── index.ts # Main export
│ ├── *.types.ts # TypeScript types
│ └── plugin/ # Expo config plugin
├── example/ # Example app for testing
└── package.jsonWhy This Package?
- Modern APIs: Uses the latest Android Credential Manager instead of deprecated GoogleSignInClient
- Simple Setup: Automatic configuration via Expo config plugin
- Secure: Includes server-side ID token verification on Android
- Well-Typed: Full TypeScript support with proper types
- Maintained: Built for Expo SDK 52+ with React Native's new architecture support
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Author
Kevin Jossendal - @kjossendal
