From 3875f48273032c9f78b5c460527fa14e0dac9be0 Mon Sep 17 00:00:00 2001 From: Eliot Gevers Date: Sat, 15 Aug 2026 01:43:05 -0700 Subject: [PATCH] fix(expo-google-signin): preserve provider failures --- .changeset/preserve-google-sign-in-errors.md | 5 ++++ .../expo-google-signin/android/build.gradle | 1 + .../googlesignin/ClerkGoogleSignInModule.kt | 23 ++++++++++++++++--- .../ClerkGoogleSignInModuleTest.kt | 21 +++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 .changeset/preserve-google-sign-in-errors.md create mode 100644 packages/expo-google-signin/android/src/test/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModuleTest.kt diff --git a/.changeset/preserve-google-sign-in-errors.md b/.changeset/preserve-google-sign-in-errors.md new file mode 100644 index 00000000000..1fe1638a22b --- /dev/null +++ b/.changeset/preserve-google-sign-in-errors.md @@ -0,0 +1,5 @@ +--- +'@clerk/expo-google-signin': patch +--- + +Fix Android Google Sign-In provider failures being reported as user cancellation. diff --git a/packages/expo-google-signin/android/build.gradle b/packages/expo-google-signin/android/build.gradle index 81ad78c0c7a..bfa50c59cf5 100644 --- a/packages/expo-google-signin/android/build.gradle +++ b/packages/expo-google-signin/android/build.gradle @@ -36,4 +36,5 @@ dependencies { implementation "androidx.credentials:credentials-play-services-auth:1.3.0" implementation "com.google.android.libraries.identity.googleid:googleid:1.1.1" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" + testImplementation "junit:junit:4.13.2" } diff --git a/packages/expo-google-signin/android/src/main/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModule.kt b/packages/expo-google-signin/android/src/main/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModule.kt index 68be6942cf4..85cc3ab13f6 100644 --- a/packages/expo-google-signin/android/src/main/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModule.kt +++ b/packages/expo-google-signin/android/src/main/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModule.kt @@ -98,7 +98,7 @@ class ClerkGoogleSignInModule : Module() { handleSignInResult(result, promise) } catch (e: GetCredentialCancellationException) { - promise.reject("SIGN_IN_CANCELLED", "User cancelled the sign-in flow", e) + rejectCredentialCancellation(promise, e) } catch (e: NoCredentialException) { promise.reject("NO_SAVED_CREDENTIAL_FOUND", "No saved credential found", e) } catch (e: GetCredentialException) { @@ -145,7 +145,7 @@ class ClerkGoogleSignInModule : Module() { handleSignInResult(result, promise) } catch (e: GetCredentialCancellationException) { - promise.reject("SIGN_IN_CANCELLED", "User cancelled the sign-in flow", e) + rejectCredentialCancellation(promise, e) } catch (e: NoCredentialException) { promise.reject("NO_SAVED_CREDENTIAL_FOUND", "No saved credential found", e) } catch (e: GetCredentialException) { @@ -191,7 +191,7 @@ class ClerkGoogleSignInModule : Module() { handleSignInResult(result, promise) } catch (e: GetCredentialCancellationException) { - promise.reject("SIGN_IN_CANCELLED", "User cancelled the sign-in flow", e) + rejectCredentialCancellation(promise, e) } catch (e: GetCredentialException) { promise.reject("GOOGLE_SIGN_IN_ERROR", e.message ?: "Unknown error", e) } catch (e: Exception) { @@ -215,6 +215,17 @@ class ClerkGoogleSignInModule : Module() { // MARK: - Helpers + private fun rejectCredentialCancellation(promise: Promise, exception: GetCredentialCancellationException) { + val message = exception.message ?: "Google Sign-In failed" + + if (isExplicitUserCancellation(message)) { + promise.reject("SIGN_IN_CANCELLED", "User cancelled the sign-in flow", exception) + return + } + + promise.reject("GOOGLE_SIGN_IN_ERROR", message, exception) + } + private fun handleSignInResult(result: GetCredentialResponse, promise: Promise) { when (val credential = result.credential) { is CustomCredential -> { @@ -255,3 +266,9 @@ class ClerkGoogleSignInModule : Module() { } } } + +private val explicitUserCancellationPattern = + Regex("^(?:\\[\\d+]\\s*)?cancel(?:l)?ed by user\\.?$", RegexOption.IGNORE_CASE) + +internal fun isExplicitUserCancellation(message: String): Boolean = + explicitUserCancellationPattern.matches(message.trim()) diff --git a/packages/expo-google-signin/android/src/test/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModuleTest.kt b/packages/expo-google-signin/android/src/test/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModuleTest.kt new file mode 100644 index 00000000000..61dcac7ac73 --- /dev/null +++ b/packages/expo-google-signin/android/src/test/java/expo/modules/clerk/googlesignin/ClerkGoogleSignInModuleTest.kt @@ -0,0 +1,21 @@ +package expo.modules.clerk.googlesignin + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class ClerkGoogleSignInModuleTest { + @Test + fun identifiesExplicitUserCancellation() { + assertTrue(isExplicitUserCancellation("[16] Cancelled by user.")) + assertTrue(isExplicitUserCancellation("Canceled by user")) + assertTrue(isExplicitUserCancellation(" cancelled by user ")) + } + + @Test + fun preservesProviderFailures() { + assertFalse(isExplicitUserCancellation("[16] Account reauth failed.")) + assertFalse(isExplicitUserCancellation("Developer console is not set up correctly.")) + assertFalse(isExplicitUserCancellation("Request was not cancelled by user")) + } +}