I have successfully integrated CredentialManager on Android. Suppose the user sign in for first time , I get the required details like email. Now the user completely closes the app and once he reopens again how to check if the user has already signed in using credential manager as well as get the email id of the signed in user, please note that the user has not logged out and has only closed the app completely from background. Here is my code
class MainActivity : AppCompatActivity() {
private lateinit var googleIdOption: GetGoogleIdOption
private lateinit var loginBtn: Button
private lateinit var textView: TextView
private lateinit var logoutBtn: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
loginBtn = findViewById(R.id.btn)
textView = findViewById(R.id.textview)
logoutBtn = findViewById(R.id.logout)
val credentialManager = CredentialManager.create(this)
logoutBtn.setOnClickListener {
lifecycleScope.launch {
userPreferencesDataStore.edit {
it.clear()
}
val request = ClearCredentialStateRequest()
credentialManager.clearCredentialState(request)
}
}
loginBtn.setOnClickListener {
val rawNonce = UUID.randomUUID().toString()
val bytes = rawNonce.toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val digest = md.digest(bytes)
val hashedNonce = digest.fold(""){str, it -> str + "%02x".format(it)}
googleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false) //IMP Part
.setServerClientId("myapikey.apps.googleusercontent.com")
.setAutoSelectEnabled(true)
.setNonce(hashedNonce)
.build()
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
lifecycleScope.launch {
try {
val result = credentialManager.getCredential(
request = request,
context = this@MainActivity,
)
handleSignIn(result)
} catch (e: GetCredentialException) {
Log.e("Erroris", "Error getting credential", e)
}
}
}
}
private fun handleSignIn(result: GetCredentialResponse) {
// Handle the successfully returned credential.
when (val credential = result.credential) {
// Passkey credential
is PublicKeyCredential -> {
// Share responseJson such as a GetCredentialResponse on your server to
// validate and authenticate
val responseJson = credential.authenticationResponseJson
}
// Password credential
is PasswordCredential -> {
// Send ID and password to your server to validate and authenticate.
val username = credential.id
val password = credential.password
}
// GoogleIdToken credential
is CustomCredential -> {
if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
// Use googleIdTokenCredential and extract id to validate and
// authenticate on your server.
val googleIdTokenCredential = GoogleIdTokenCredential
.createFrom(credential.data)
val googleIdToken = googleIdTokenCredential.idToken
Log.i("answer",googleIdToken)
val personId = googleIdTokenCredential.id
Log.i("answer",personId) //email
val displayName = googleIdTokenCredential.displayName
Log.i("answer",displayName.toString())
val personPhoto = googleIdTokenCredential.profilePictureUri
Log.i("answer",personPhoto.toString())
} catch (e: GoogleIdTokenParsingException) {
Log.e("Erroris", "Received an invalid google id token response", e)
}
} else {
// Catch any unrecognized custom credential type here.
Log.e("Erroris", "Unexpected type of credential")
}
}
else -> {
// Catch any unrecognized credential type here.
Log.e("Erroris", "Unexpected type of credential")
}
}
}
}
The recommendation, as stated here, is to always call the API with .setFilterByAuthorizedAccounts(true)
(with also .setAutoSelectEnabled(true)
) first and then if you get a response to the effect that there was no credential, then call the same method but use .setFilterByAuthorizedAccounts(false)
. When you call the api with .setFilterByAuthorizedAccounts(true)
, you are basically asking for only those accounts that have already been used to sign into your app (i.e. user has already given the consent to share some info for that account with your app). If such an account is there (and if there is only one such an account on that device), then the parameter set by setting .setAutoSelectEnabled(true)
allows the flow to move forward without any user interaction and at the end, it returns an ID Token to you, from which you can extract the email of that account.