We are using Fido2ApiClient in our Android app to perform FIDO-based authentication (QR-based account registration + biometric authentication).
We observed an issue where on some Android devices, after scanning a QR code and starting FIDO registration, the biometric prompt (fingerprint/PIN/pattern) was not shown, so the registration flow could not proceed.

[Figure] On some devices, the biometric prompt is not displayed after Fido2ApiClient call
Key observations:
- The issue occurred only on some specific devices, not on all devices.
- Clearing Google Play services data on affected devices resolved the issue immediately.
- After April 9, we confirmed that all previously affected devices were working normally without any action on our side (no app update, no manual reset).
Timeline:
- Until April 7: The issue was reproducible on affected devices.
- After April 9: The issue was no longer reproducible, and all previously affected devices were working normally.
We also checked Google Play services release notes around that period, but we could not find any explicit mention related to FIDO2, biometric prompt behavior, or the authentication flow.
https://developers.google.com/android/guides/releases?utm_source=chatgpt.com&hl=ko#april_09_2026
https://support.google.com/product-documentation/answer/14343500?hl=en&utm_source=chatgpt.com#zippy=
For reference, below is the part of our implementation that invokes Fido2ApiClient for FIDO registration.
private void fido2RegisterStart() {
Log.d(TAG, "[FIDO] fido2RegisterStart entered");
PublicKeyCredentialCreationOptions options = null;
try {
JSONObject response = AMDataManager.getResponseData();
JSONObject jsonOptions = new JSONObject(response.getString("publicKeyCredentialCreationOptions"));
String challenge = jsonOptions.getString("challenge");
byte[] challengeByte = AMBase64.decode(challenge);
String rpId = jsonOptions.getJSONObject("rp").getString("id");
String rpName = jsonOptions.getJSONObject("rp").getString("name");
if (rpName == null || rpName.equals("null") || rpName.isEmpty()) {
rpName = "miraeasset";
}
String rpIcon = null;
String userName = jsonOptions.getJSONObject("user").getString("name");
String displayName = jsonOptions.getJSONObject("user").getString("displayName");
String userId = jsonOptions.getJSONObject("user").getString("id");
byte[] userIdBytes = AMBase64.decode(userId);
options = new PublicKeyCredentialCreationOptions.Builder()
.setRp(new PublicKeyCredentialRpEntity(rpId, rpName, rpIcon))
.setUser(new PublicKeyCredentialUserEntity(
userIdBytes, // userId.getBytes(),
userName,
null,
displayName
))
.setChallenge(challengeByte)
.setParameters(
listOf(
new PublicKeyCredentialParameters(
PublicKeyCredentialType.PUBLIC_KEY.toString(),
EC2Algorithm.ES256.getAlgoValue()
)
)
)
.setAuthenticatorSelection(
new AuthenticatorSelectionCriteria.Builder()
.setRequireResidentKey(true)
.setAttachment(Attachment.PLATFORM)
.build()
)
.build();
Log.d(TAG, "[FIDO] options created = " + (options != null));
Fido2ApiClient fido2ApiClient = Fido.getFido2ApiClient(requireContext());
PublicKeyCredentialCreationOptions finalOptions = options;
fido2ApiClient.isUserVerifyingPlatformAuthenticatorAvailable()
.addOnSuccessListener(isAvailable -> {
Log.d(TAG, "[FIDO] isAvailable = " + isAvailable);
Log.d(TAG, "[FIDO] finalOptions = " + finalOptions);
startRegisterFlow(fido2ApiClient, finalOptions);
})
.addOnFailureListener(e -> {
Log.e(TAG, "[FIDO] isAvailable failed", e);
});
} catch (JSONException e) {
Log.e(TAG, "[FIDO] JSONException in fido2RegisterStart", e);
return;
}
}
private void startRegisterFlow(Fido2ApiClient fido2ApiClient,
PublicKeyCredentialCreationOptions options) {
Log.d(TAG, "[FIDO] getRegisterPendingIntent call");
Task<PendingIntent> result = fido2ApiClient.getRegisterPendingIntent(options);
result.addOnSuccessListener(pendingIntent -> {
Log.d(TAG, "[FIDO] getRegisterPendingIntent success, pendingIntent=" + (pendingIntent != null));
if (pendingIntent != null) {
try {
Log.d(TAG, "[FIDO] startIntentSenderForResult call");
requireActivity().startIntentSenderForResult(
pendingIntent.getIntentSender(),
REQUEST_CODE_REGISTER,
null,
0,
0,
0
);
Log.d(TAG, "[FIDO] startIntentSenderForResult done");
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "[FIDO] startIntentSenderForResult failed", e);
}
} else {
Log.e(TAG, "[FIDO] pendingIntent is null");
}
});
result.addOnFailureListener(e -> {
Log.e(TAG, "[FIDO] getRegisterPendingIntent failure", e);
});
}
Questions:
1. Could this issue have been related to an internal update or fix in Google Play services that was not explicitly documented?
2. Is it possible that a Google Play services update triggered an internal state refresh or recovery that affected FIDO2 flows?
3. Are there any known issues related to Fido2ApiClient where the biometric prompt is not shown under certain conditions?
Any insights would be greatly appreciated.
Thank you.
--
You received this message because you are subscribed to the Google Groups "FIDO Dev (fido-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fido-dev+u...@fidoalliance.org.
To view this discussion visit https://groups.google.com/a/fidoalliance.org/d/msgid/fido-dev/08b8fcbd-a895-44c0-abbd-f57ff7665740n%40fidoalliance.org.
--
You received this message because you are subscribed to the Google Groups "FIDO Dev (fido-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fido-dev+u...@fidoalliance.org.
To view this discussion visit https://groups.google.com/a/fidoalliance.org/d/msgid/fido-dev/f0f43240-bba6-4c66-93f8-1b3f4d29c32dn%40fidoalliance.org.
Bahasa.indonesia.