androidkotlingoogle-signin

Google Credential Manager - Issue with getting the user email


I'm using the Android Credential Manager API to implement "Sign In with Google" in my application. I'm successfully getting a GoogleIdTokenCredential after a successful sign-in, but I'm encountering an issue where I cannot get the user's email address.

Here's the relevant code:

@Composable
fun SignInWithGoogleButton(modifier: Modifier = Modifier) {
    val context = LocalContext.current
    val credentialManager = remember(context) { CredentialManager.create(context) }
    val coroutineScope = rememberCoroutineScope()

    val WEB_CLIENT_ID = "[MyId]" 

    Button(
        onClick = {
            coroutineScope.launch {
                try {
                    val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption.Builder(serverClientId = WEB_CLIENT_ID)
                        // add the nonce later
                        .build()

                    val request: GetCredentialRequest = GetCredentialRequest.Builder()
                        .addCredentialOption(signInWithGoogleOption)
                        .build()

                    val result = credentialManager.getCredential(
                        context = context,
                        request = request
                    )

                    handleSignInWithGoogleResult(result)

                } catch (e: GetCredentialException) {
                    Log.e("GoogleSignIn", "Credential Manager Sign in with Google failed: ${e.message}", e)
                } catch (e: Exception) {
                    Log.e("GoogleSignIn", "An unexpected error occurred: ${e.message}", e)
                }
            }
        }
    )
    {
        Text("Sign In with Google")
    }
}

private fun handleSignInWithGoogleResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is CustomCredential -> {
            if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
                try {
                    val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
                    val idToken = googleIdTokenCredential.idToken
                    val email = googleIdTokenCredential.id
                    val displayName = googleIdTokenCredential.displayName

                    Log.d("GoogleSignIn", "ID Token: $idToken")
                    Log.d("GoogleSignIn", "Email (from googleIdTokenCredential.id): $email")
                    Log.d("GoogleSignIn", "Display Name: $displayName")

                } catch (e: GoogleIdTokenParsingException) {
                    Log.e("GoogleSignIn", "Failed to parse Google ID token credential: ${e.message}", e)
                }
            } else {
                Log.e("GoogleSignIn", "Unexpected type of CustomCredential: ${credential.type}")
            }
        }
        else -> {
            Log.e("GoogleSignIn", "Unexpected type of credential: ${credential.type}")
        }
    }
}

Dependencies

    implementation("androidx.credentials:credentials:1.5.0")
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0")
    implementation("com.google.android.libraries.identity.googleid:googleid:1.1.1")

Problem:

  1. When I access googleIdTokenCredential.id, I receive a numerical identifier, not the user's email address.
  2. Upon inspecting the idToken string (by decoding it as a JWT), the email claim within the ID token's payload is null.

My Google Cloud Console Configuration:

In my Google Cloud Project, I have the following scopes configured:

I've tested this with two different Gmail accounts, and the behavior is consistent.

Question:

How can I correctly obtain the user's email address from the GoogleIdTokenCredential when using the Android Credential Manager, ensuring that the idToken contains the necessary claim? Is there a specific way to request these scopes within the GetSignInWithGoogleOption or GetCredentialRequest that I'm missing?

Any guidance or examples would be greatly appreciated!

What I've already try:


Solution

  • I suggest you call AuthorizationClient#revokeAccess() for that account and try again. Note that the revokeAccess() method is new in the latest version of play-services:-auth:21.4.0, or revoke access to that app for that user from https://myaccount.google.com/connections (and wait a bit for that to sync to your device).