Create GoogleSignInHelper.kt — the Google ID token
In the code column — GoogleSignInHelper.kt. One suspend function: CredentialManager shows the Google account picker, and if the user chooses one — it returns an ID token (a signed JWT). Note setServerClientId(...google_web_client_id) — we pass the Web client ID here, not the Android one.
Add the dependencies and strings.xml:
implementation(libs.androidx.credentials)
implementation(libs.androidx.credentials.play.services.auth)
implementation(libs.googleid) // GetGoogleIdOption
<!-- res/values/strings.xml -->
<string name="google_web_client_id">1001517404205-...apps.googleusercontent.com</string>
Next — the same contract as 8a. PicaApi gains the endpoint:
@POST("auth/google")
suspend fun googleAuth(@Body request: GoogleAuthRequest): AuthResponse // ← the same AuthResponse!
@Serializable data class GoogleAuthRequest(@SerialName("id_token") val idToken: String)
AuthRepository — a new function that saves the token to the same store:
suspend fun googleSignIn(idToken: String) {
val response = api.googleAuth(GoogleAuthRequest(idToken))
tokenStorage.saveToken(response.token) // same storage as email/password
}
AuthViewModel — googleSignIn(idToken) mirrors the authenticate() logic (isLoading, isLoggedIn, error). And LoginScreen — a button below an "or" divider:
OutlinedButton(
onClick = {
scope.launch {
try {
val idToken = getGoogleIdToken(context)
if (idToken != null) viewModel.googleSignIn(idToken)
} catch (e: Exception) {
// user dismissed the picker or no accounts available — ignore
}
}
},
enabled = !state.isLoading,
modifier = Modifier.fillMaxWidth()
) { Text("Sign in with Google") }
Tip.
setFilterByAuthorizedAccounts(false)shows all the phone's Google accounts (not just ones previously used with this app).trueis nice for "returning" users (a quieter flow), but a first sign-in needsfalse.