Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 36 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ import { GoogleAuth, GoogleAuthScopes } from 'react-native-google-auth';

// Configure once in your app
await GoogleAuth.configure({
iosClientId: 'YOUR_IOS_CLIENT_ID',
androidClientId: 'YOUR_ANDROID_CLIENT_ID',
iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com',
androidClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com', // Use Web OAuth client ID for Android
scopes: [GoogleAuthScopes.EMAIL, GoogleAuthScopes.PROFILE]
});

Expand All @@ -97,6 +97,8 @@ if (response.type === 'success') {
}
```

> **Android Note:** The `androidClientId` must be a **Web application OAuth client ID** (not Android OAuth client), as required by the Android Credential Manager API.

## 📱 Platform Setup

### Expo Setup (Recommended)
Expand Down Expand Up @@ -344,19 +346,23 @@ interface GoogleAuthPluginOptions {
1. **Configure Client ID (Choose one method):**

**Method A: Automatic Detection from google-services.json (Recommended)**

Add your `google-services.json` file to `android/app/` directory.

> **Important:** The library will automatically extract the Web client ID (client_type: 3) from your `google-services.json`. This is the correct client ID for Android Credential Manager authentication.

**Method B: Manual Configuration**
Provide the client ID directly in your configuration:

Provide the **Web application** client ID directly in your configuration:
```typescript
await GoogleAuth.configure({
androidClientId: 'YOUR_ANDROID_CLIENT_ID.apps.googleusercontent.com',
androidClientId: 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com', // Use Web OAuth client ID, NOT Android client ID
iosClientId: 'YOUR_IOS_CLIENT_ID.apps.googleusercontent.com'
});
```

> **Note:** The `androidClientId` should be your **Web application OAuth client ID** (client_type: 3 in google-services.json), not the Android OAuth client ID. The Android OAuth client is used only for linking your SHA-1 certificate to the project.

## 🔧 Google Cloud Console Setup

### Step 1: Create a Google Cloud Project
Expand Down Expand Up @@ -387,29 +393,45 @@ interface GoogleAuthPluginOptions {
6. Copy the **Client ID** (ends with `.apps.googleusercontent.com`)

#### For Android:

**Important:** For Android, you need to create **both** an Android OAuth client AND a Web application OAuth client.

**Step 1: Create Android OAuth Client (for SHA-1 certificate)**
1. Go to **Credentials** → **Create Credentials** → **OAuth 2.0 Client IDs**
2. Application type: **Android**
3. Name: Your app name (Android)
4. Package name: Your Android app's package name (e.g., `com.yourcompany.yourapp`)
5. SHA-1 certificate fingerprint:

**For development:**
```bash
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
```

**For Expo development builds:**
```bash
eas credentials -p android
```

**For production:**
```bash
keytool -list -v -keystore path/to/your/release.keystore -alias your-key-alias
```

6. Click **Create**
7. Copy the **Client ID** (ends with `.apps.googleusercontent.com`)

**Step 2: Create Web Application OAuth Client (Required for Android Authentication)**
1. Go to **Credentials** → **Create Credentials** → **OAuth 2.0 Client IDs**
2. Application type: **Web application**
3. Name: Your app name (Web)
4. Click **Create**
5. **Copy this Client ID** - this is what you'll use for `androidClientId` in your configuration

> **Why do I need a Web client ID for Android?**
>
> The Android Credential Manager API requires a Web OAuth client ID (client_type: 3) for authentication. This is used to generate ID tokens and authenticate with your backend server. The Android OAuth client (created in Step 1) is only used for associating your app's package name and SHA-1 certificate with your project.
>
> When you download `google-services.json`, look for the `oauth_client` entry with `"client_type": 3` - this is the Web client ID you should use in your `androidClientId` configuration.

### Step 4: Download Configuration Files (Optional but Recommended)

Expand Down Expand Up @@ -673,8 +695,10 @@ enum GoogleAuthScopes {

**1. "DEVELOPER_ERROR" on Android**
- Verify your package name matches Google Cloud Console
- Check SHA-1 fingerprint is correctly added
- Ensure `google-services.json` is in the correct location
- Check SHA-1 fingerprint is correctly added to the Android OAuth client
- Ensure you're using the **Web application OAuth client ID** (client_type: 3), not the Android OAuth client ID
- Verify `google-services.json` is in the correct location (`android/app/`)
- If manually configuring, ensure `androidClientId` is set to your Web OAuth client ID

**2. "SIGN_IN_REQUIRED" error**
- User needs to sign in first
Expand Down
28 changes: 21 additions & 7 deletions ios/GoogleAuth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import GoogleSignIn

@objc(GoogleAuth)
class GoogleAuth: NSObject {

@objc static let shared = GoogleAuth()
private var isConfigured = false

private var configuredScopes: [String] = []

private var forceAccountPicker: Bool = false

private override init() {
super.init()
}
Expand Down Expand Up @@ -44,7 +45,13 @@ class GoogleAuth: NSObject {
if let scopes = params["scopes"] as? [String] {
validateAndStoreScopes(scopes)
}


// Store forceAccountPicker preference
if let forceAccountPicker = params["forceAccountPicker"] as? Bool {
self.forceAccountPicker = forceAccountPicker
print("GoogleAuth: forceAccountPicker set to \(forceAccountPicker)")
}

isConfigured = true
print("GoogleAuth: Configuration completed successfully")
} catch {
Expand All @@ -61,21 +68,28 @@ class GoogleAuth: NSObject {
reject("NOT_CONFIGURED", "GoogleAuth must be configured before signing in", nil)
return
}

DispatchQueue.main.async {
guard let presentingViewController = self.getPresentingViewController() else {
reject("NO_VIEW_CONTROLLER", "No presenting view controller found", nil)
return
}


// If forceAccountPicker is enabled, skip silent sign-in and show account picker directly
if self.forceAccountPicker {
print("GoogleAuth: forceAccountPicker enabled, skipping silent sign-in")
self.performInteractiveSignIn(presentingViewController: presentingViewController, resolve: resolve, reject: reject)
return
}

// Try silent sign-in first
GIDSignIn.sharedInstance.restorePreviousSignIn { [weak self] result, error in
if let error = error {
// No previous sign-in, show interactive sign-in
self?.performInteractiveSignIn(presentingViewController: presentingViewController, resolve: resolve, reject: reject)
return
}

if let user = result {
self?.handleSignInSuccess(user: user, resolve: resolve)
} else {
Expand Down
9 changes: 9 additions & 0 deletions src/NativeGoogleAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,15 @@ export interface ConfigureParams {
* Legacy parameter for specific use cases
*/
openIdRealm?: string;

/**
* Force the account picker to show even if a user is already signed in
* When true, skips silent sign-in and always shows the account selection UI
* Useful when you want users to explicitly choose between multiple Google accounts
* Default: false
* @platform iOS
*/
forceAccountPicker?: boolean;
}

export interface User {
Expand Down
Loading