Harden Google sign-in when backend auth fails
Sign out of Firebase and clear API and local profile if the GraphQL exchange or token save fails after Firebase Google sign-in, so the user is not left in a half-authenticated state. Rename the exchange helper to exchangeFirebaseIdTokenWithBackend for clarity. Login: ignore duplicate Google taps while loading and disable the Google button during the flow. Credential Manager: treat GetCredentialInterruptedException as cancellation and rethrow CancellationException so coroutines cancel correctly. Tests: assert signOut is invoked when the backend exchange fails. Made-with: Cursor
This commit is contained in:
@@ -15,6 +15,7 @@ import androidx.credentials.exceptions.NoCredentialException
|
||||
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
|
||||
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
|
||||
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
import org.db3.airmq.R
|
||||
|
||||
sealed interface GoogleSignInResult {
|
||||
@@ -51,12 +52,17 @@ suspend fun launchGoogleSignIn(context: Context): GoogleSignInResult {
|
||||
} catch (error: GetCredentialCancellationException) {
|
||||
logGoogleSignInError(error)
|
||||
GoogleSignInResult.Cancelled
|
||||
} catch (error: GetCredentialInterruptedException) {
|
||||
logGoogleSignInError(error)
|
||||
GoogleSignInResult.Cancelled
|
||||
} catch (error: GetCredentialException) {
|
||||
logGoogleSignInError(error)
|
||||
GoogleSignInResult.Error(context.getString(R.string.toast_oauth_failed))
|
||||
} catch (error: GoogleIdTokenParsingException) {
|
||||
Log.e(GOOGLE_SIGN_IN_TAG, "Google ID token parsing failed", error)
|
||||
GoogleSignInResult.Error(context.getString(R.string.toast_oauth_failed))
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (error: Throwable) {
|
||||
GoogleSignInResult.Error(error.message ?: context.getString(R.string.toast_oauth_failed))
|
||||
}
|
||||
|
||||
@@ -213,6 +213,7 @@ private fun LoginScreenContent(
|
||||
containerColor = Color.White,
|
||||
contentColor = Color(0xFF202124),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
enabled = !uiState.isLoading,
|
||||
onClick = { onEvent(Event.GoogleClicked) }
|
||||
)
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class LoginViewModel @Inject constructor(
|
||||
fun onEvent(event: Event) {
|
||||
when (event) {
|
||||
Event.GoogleClicked -> {
|
||||
if (_uiState.value.isLoading) return
|
||||
_uiState.value = _uiState.value.copy(isLoading = true)
|
||||
_actions.tryEmit(Action.LaunchGoogleSignIn)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user