diff --git a/android/src/main/java/com/googleauth/GoogleAuthModule.kt b/android/src/main/java/com/googleauth/GoogleAuthModule.kt index 84df363..a335eab 100644 --- a/android/src/main/java/com/googleauth/GoogleAuthModule.kt +++ b/android/src/main/java/com/googleauth/GoogleAuthModule.kt @@ -46,6 +46,7 @@ class GoogleAuthModule(reactContext: ReactApplicationContext) : private var androidClientId: String? = null private var hostedDomain: String? = null private var configuredScopes: List? = null + private var credentialManagerMode: String = "auto" // 'silent', 'interactive', or 'auto' private var isConfigured = false private val coroutineScope = CoroutineScope(Dispatchers.Main) @@ -125,7 +126,16 @@ class GoogleAuthModule(reactContext: ReactApplicationContext) : webClientId = params.getString("webClientId") androidClientId = params.getString("androidClientId") hostedDomain = params.getString("hostedDomain") - + + // Extract credential manager mode (default to "auto" if not specified) + credentialManagerMode = params.getString("credentialManagerMode") ?: "auto" + + // Validate credential manager mode + if (credentialManagerMode !in listOf("silent", "interactive", "auto")) { + promise.reject("INVALID_CONFIG", "credentialManagerMode must be 'silent', 'interactive', or 'auto'") + return + } + // Extract and validate scopes val scopesArray = params.getArray("scopes") configuredScopes = scopesArray?.let { array -> @@ -192,18 +202,43 @@ class GoogleAuthModule(reactContext: ReactApplicationContext) : return@launch } - // Try silent sign-in first - try { - val silentResult = performSilentSignIn(activity) - withContext(Dispatchers.Main) { - promise.resolve(silentResult) + when (credentialManagerMode) { + "silent" -> { + // Silent mode only - no fallback to interactive + try { + val silentResult = performSilentSignIn(activity) + withContext(Dispatchers.Main) { + promise.resolve(silentResult) + } + } catch (e: Exception) { + Log.e("GoogleAuth", "Silent sign-in failed: " + (e.localizedMessage ?: "Unknown error")) + withContext(Dispatchers.Main) { + promise.reject("SIGN_IN_ERROR", "Silent sign-in failed. No saved credentials found or user not previously authorized: " + (e.localizedMessage ?: "Unknown error"), e) + } + } + } + "interactive" -> { + // Interactive mode only - always show account picker + val interactiveResult = performInteractiveSignIn(activity) + withContext(Dispatchers.Main) { + promise.resolve(interactiveResult) + } } - } catch (e: Exception) { - Log.d("GoogleAuth", "Silent sign-in failed, trying interactive: " + (e.localizedMessage ?: "Unknown error")) - // If silent fails, try interactive - val interactiveResult = performInteractiveSignIn(activity) - withContext(Dispatchers.Main) { - promise.resolve(interactiveResult) + else -> { + // Auto mode (default) - try silent first, fallback to interactive + try { + val silentResult = performSilentSignIn(activity) + withContext(Dispatchers.Main) { + promise.resolve(silentResult) + } + } catch (e: Exception) { + Log.d("GoogleAuth", "Silent sign-in failed, trying interactive: " + (e.localizedMessage ?: "Unknown error")) + // If silent fails, try interactive + val interactiveResult = performInteractiveSignIn(activity) + withContext(Dispatchers.Main) { + promise.resolve(interactiveResult) + } + } } } } catch (e: Exception) { diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index ae6c0e1..fc3e368 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -11,7 +11,7 @@ PODS: - FBLazyVector (0.81.0) - fmt (11.0.2) - glog (0.3.5) - - GoogleAuth (2.1.0): + - GoogleAuth (1.2.1): - boost - DoubleConversion - fast_float @@ -2598,7 +2598,7 @@ SPEC CHECKSUMS: FBLazyVector: a867936a67af0d09c37935a1b900a1a3c795b6d1 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 - GoogleAuth: d45f30ae4d49edbaf5e48d56586e164b925bf004 + GoogleAuth: eec941506f196ee17b5e9a74a3b83e720d599232 GoogleSignIn: d4281ab6cf21542b1cfaff85c191f230b399d2db GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 @@ -2665,7 +2665,7 @@ SPEC CHECKSUMS: React-timing: 25e8229ad1cf6874e9f0711515213cb2bc322215 React-utils: 068cec677032ba78ca0700f2dcbe6d08a0939647 ReactAppDependencyProvider: c91900fa724baee992f01c05eeb4c9e01a807f78 - ReactCodegen: 5695f203204e30acbf7d6c06dbb8d0f391e52133 + ReactCodegen: a55799cae416c387aeaae3aabc1bc0289ac19cee ReactCommon: 116d6ee71679243698620d8cd9a9042541e44aa6 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: 00013dd9cde63a2d98e8002fcc4f5ddb66c10782 diff --git a/src/NativeGoogleAuth.ts b/src/NativeGoogleAuth.ts index 898058d..6546fa6 100644 --- a/src/NativeGoogleAuth.ts +++ b/src/NativeGoogleAuth.ts @@ -118,6 +118,16 @@ export interface ConfigureParams { * @platform iOS */ forceAccountPicker?: boolean; + + /** + * Android Credential Manager behavior mode + * - 'silent': Only show existing authorized accounts, no UI interaction + * - 'interactive': Always display the Google account picker UI + * - 'auto': Try silent sign-in first, fallback to interactive if needed (default) + * Default: 'auto' + * @platform Android + */ + credentialManagerMode?: 'silent' | 'interactive' | 'auto'; } export interface User {