Hybrid Sign-In
Introduction
Hybrid sign-in is a user-friendly approach that combines the best of native and app-level authentication. It relies entirely on the platform's built-in sign-in methods, giving users a seamless and familiar experience and making the app feel like a world-class app.
A good UX is to dispatch hybrid sign-in immediately on app start. If any error occurs or user cancels, fall back to a custom UI with your desired authentication flow.
⚠️ Important:
- Users cannot choose the platform methods - the OS presents available credentials
- Android: Google ID must be configured (
webClientId, passed or in the app config). iOS: the client id is ignored, Google is not offered- Always handle the
CANCELLEDcase - users may dismiss the credential picker
We highly recommend using hybrid sign-in as the default for unauthenticated users, while still providing alternative sign-in options to cover all cases.
Platform Support
iOS
- Offers: Apple ID and saved passwords (
ASAuthorizationController). Google ID is not included - On iOS 16+ only credentials already on the device are offered
- Resolves
CANCELLEDwhen the user dismisses it or nothing is available - Only
options.nonceis used (for Apple ID); the client id and other options log a warning in development - Ideal for app launch to restore previous session
Android
- Offers: Google ID (
GetGoogleIdOption) and saved passwords. Apple ID is not included (useappleSignIn()) - Uses Credential Manager to aggregate the options in one bottom sheet
- Requires Google Play Services: rejects with
NOT_SUPPORTED_ERRORwithout them (HYBRID_SUPPORTEDisfalsethen) - Uses
webClientId, or the web client id from the app config (manifest meta-data or Firebase); rejects withCONFIGURATION_ERRORwithout any authorizedAccounts,autoSelectEnabledandnonceare used;mode,hint,scopes,offlineAccess,hostedDomainandserverClientIdare ignored (with a warning in development)
Methods
hybridSignIn(clientId?: GoogleClientId | null, options?: GoogleSignInOptions)
Performs all available sign-in methods on the platform at once. Also callable as hybridSignIn() and
hybridSignIn(options) when the web client id is in the app config.
This is typically used on app startup to retrieve any existing sign-in credentials.
Parameters
| Name | Type | Description |
|---|---|---|
clientId | GoogleClientId (optional) | Same as googleSignIn: { iosClientId, webClientId } or a string, or omitted to read it from the app config. Android uses webClientId; ignored on iOS. See Google client ids. |
options | GoogleSignInOptions (optional) | Optional configuration for Google Sign-In. See GoogleSignInOptions for details. |
GoogleSignInOptions
type GoogleSignInOptions = {
authorizedAccounts?: boolean; // Android only: Filter to authorized accounts
autoSelectEnabled?: boolean; // Android only: Enable auto-selection
nonce?: string; // Android: Google idToken nonce. iOS: Apple ID nonce
};
Other GoogleSignInOptions fields are ignored by hybridSignIn.
Returns
Promise<AppleIdCredentialResult | GoogleIdCredentialResult | PasswordCredentialResult | CancelledCredentialResult>
The promise resolves to whichever credential is available on the platform:
GoogleIdCredentialResult (Android only):
{
type: CredentialsType.GOOGLE_ID;
data: {
id: string;
idToken: string;
displayName: string;
givenName: string;
familyName: string;
profilePictureUri?: string | null;
phoneNumber?: string | null;
};
}
AppleIdCredentialResult (iOS only):
{
type: CredentialsType.APPLE_ID;
data: {
idToken: string;
authorizationCode: string;
user: string;
email: string;
fullName: string;
likelyReal: boolean;
};
}
PasswordCredentialResult:
{
type: CredentialsType.PASSWORD;
data: {
username: string;
password: string;
};
}
CancelledCredentialResult:
{
type: CredentialsType.CANCELLED;
data: null; // User dismissed the credential picker
}
Error Codes
| Error Code | Description | Platform |
|---|---|---|
CONFIGURATION_ERROR | No webClientId | Android only |
NOT_SUPPORTED_ERROR | Google Play Services not available or outdated | Android only |
NO_ACTIVITY_ERROR | No Android activity context available | Android only |
NO_SIGN_IN_AVAILABLE | No Google account or saved password for the request | Android only |
SIMULTANEOUS_CALL_ERROR | A previous hybridSignIn is still pending | iOS only |
INVALID_RESULT_ERROR | The provider failed or returned an unexpected result | Both |
Important Notes
- Check
HYBRID_SUPPORTEDbefore using hybrid sign-in: alwaystrueon iOS, same asGOOGLE_PLAY_SERVICES_SUPPORTEDon Android - On iOS, Apple ID and stored passwords may be returned
- On Android, Google ID and stored passwords may be returned (Apple requires separate Chrome Custom Tabs flow)
- Useful for automatically signing in users if credentials are already available
- User can cancel, resulting in
CancelledCredentialResult - Options
authorizedAccountsandautoSelectEnabledonly work on Android - Emits
onCredentialSuccess/onCredentialFailure
Example Usage (TypeScript)
import {
hybridSignIn,
HYBRID_SUPPORTED,
CredentialsType,
} from 'react-native-oauth-essentials';
const GOOGLE_CLIENT_IDS = {
iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com',
webClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
};
async function initAuth(): Promise<void> {
if (!HYBRID_SUPPORTED) {
console.log('Hybrid sign-in is not supported on this platform.');
// Show manual sign-in UI
return;
}
try {
const credential = await hybridSignIn(GOOGLE_CLIENT_IDS, {
authorizedAccounts: true, // Android only
autoSelectEnabled: false, // Android only
});
switch (credential.type) {
case CredentialsType.GOOGLE_ID:
console.log('Signed in with Google:', credential.data.displayName);
await authenticateWithBackend('google', credential.data.idToken);
break;
case CredentialsType.APPLE_ID:
console.log('Signed in with Apple ID:', credential.data.user);
await authenticateWithBackend('apple', credential.data.idToken);
break;
case CredentialsType.PASSWORD:
console.log('Signed in with stored password:', credential.data.username);
await authenticateWithBackend('password', credential.data.username, credential.data.password);
break;
case CredentialsType.CANCELLED:
console.log('User cancelled credential picker');
// Show manual sign-in UI
break;
}
} catch (error) {
console.error('Hybrid sign-in failed:', error);
// Show manual sign-in UI
}
}
Use Cases
1. App Launch Auto Sign-In
Perfect for restoring user session when app starts:
async function handleAppLaunch() {
try {
const credential = await hybridSignIn(GOOGLE_CLIENT_IDS);
if (credential.type !== CredentialsType.CANCELLED) {
// User has existing credentials, auto sign-in
await processCredential(credential);
navigateToHomeScreen();
} else {
// No credentials or user cancelled, show sign-in screen
navigateToSignInScreen();
}
} catch (error) {
console.error(error);
// Error occurred, show sign-in screen
navigateToSignInScreen();
}
}
2. "Continue with..." Screen
Show a single button that tries all methods:
async function handleContinueButton() {
try {
const credential = await hybridSignIn(GOOGLE_CLIENT_IDS);
if (credential.type === CredentialsType.CANCELLED) {
// User dismissed, show other sign-in options
showAlternativeSignInOptions();
return;
}
// Process the credential
await processCredential(credential);
} catch (error) {
console.error(error);
showAlternativeSignInOptions();
}
}
Best Practices
- Call on app start - Try hybrid sign-in immediately when app launches for authenticated users
- Handle cancellation - Users may dismiss the credential picker, show alternative options
- Fallback to manual UI - Always provide manual sign-in options if hybrid fails
- Check support constants - Verify
HYBRID_SUPPORTEDbefore calling - Don't repeat - If user cancels, don't immediately call hybrid again
- Fast UX - Hybrid sign-in is instant, perfect for app startup
- Platform differences - iOS includes Apple ID, Android doesn't (requires separate flow)
Recommended Flow
async function initializeApp() {
// Show splash screen
showSplashScreen();
if (!HYBRID_SUPPORTED) {
navigateToSignInScreen();
return;
}
try {
// Try hybrid sign-in silently in background
const credential = await hybridSignIn(GOOGLE_CLIENT_IDS, {
autoSelectEnabled: true, // Auto-select if only one credential (Android)
});
if (credential.type === CredentialsType.CANCELLED) {
// User cancelled or no credentials available
navigateToSignInScreen();
return;
}
// Authenticate with backend
const session = await authenticateWithBackend(credential);
if (session.valid) {
// Success! Go to home screen
navigateToHomeScreen();
} else {
// Backend rejected, show sign-in screen
navigateToSignInScreen();
}
} catch (error) {
console.error('Hybrid sign-in error:', error);
navigateToSignInScreen();
}
}
Platform-Specific Details
iOS
- Presents native iOS credential picker sheet
- Includes Apple ID if user is signed in to device
- Does not include Google ID (use
googleSilentSignIn()to restore a Google session) - Includes saved passwords from Keychain
- User can select from available options or cancel
Android (API 24+)
- Uses Credential Manager API
- Presents native Android bottom sheet
- Includes Google ID if Google Play Services available
- Includes saved passwords from Google Password Manager
- Apple ID requires separate
appleSignIn()call with Chrome Custom Tabs - Options
authorizedAccountsandautoSelectEnabledonly work on Android