Description
When a user attempts to register a passkey that already exists on the device (duplicate registration), both iOS and Android fail to map the native error to exclude-credentials-match, causing it to surface as a generic PlatformException instead of ExcludeCredentialsCanNotBeRegisteredException.
Current Behavior
iOS
PlatformException(unknown, The operation couldn't be completed.
(com.apple.AuthenticationServices.AuthorizationError error 1006.), , null)
Android
PlatformException(android-unhandled:
androidx.credentials.TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION/androidx.credentials.TYPE_INVALID_STATE_ERROR,
One of the excluded credentials exists on the local device.,
One of the excluded credentials exists on the local device., null)
In both cases, the error is not caught by PasskeyAuthenticator and falls through to the generic catch block.
Expected Behavior
The error should be mapped to exclude-credentials-match and result in ExcludeCredentialsCanNotBeRegisteredException on both platforms.
Root Cause
iOS — ErrorExtension.swift
Only WKErrorDomain with code 8 is mapped to exclude-credentials-match:
https://github.com/corbado/flutter-passkeys/blob/main/packages/passkeys/passkeys_darwin/darwin/Classes/ErrorExtension.swift
if (error.domain == "WKErrorDomain" && error.code == 8) {
code = "exclude-credentials-match"
}
The native ASAuthorizationError domain with code 1006 (matchedExcludedCredential) is not handled.
Android — MessageHandler.java
The existing check matches the error message:
if (Objects.equals(e.getMessage(),
"One of the excluded credentials exists on the local device")) {
platformException = new Messages.FlutterError("exclude-credentials-match", ...);
}
However, when the error comes as TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTION with sub-type TYPE_INVALID_STATE_ERROR, it appears to be caught by a different branch and classified as android-unhandled before reaching this check.
Suggested Fix
iOS
Add a condition for the ASAuthorizationError domain in ErrorExtension.swift:
} else if (error.domain == "com.apple.AuthenticationServices.AuthorizationError" && error.code == 1006) {
code = "exclude-credentials-match"
}
Android
Ensure that TYPE_INVALID_STATE_ERROR with the excluded credentials message is also mapped to exclude-credentials-match.
Environment
- passkeys:
2.18.0
- Flutter 3.x
Description
When a user attempts to register a passkey that already exists on the device (duplicate registration), both iOS and Android fail to map the native error to
exclude-credentials-match, causing it to surface as a genericPlatformExceptioninstead ofExcludeCredentialsCanNotBeRegisteredException.Current Behavior
iOS
Android
In both cases, the error is not caught by
PasskeyAuthenticatorand falls through to the generic catch block.Expected Behavior
The error should be mapped to
exclude-credentials-matchand result inExcludeCredentialsCanNotBeRegisteredExceptionon both platforms.Root Cause
iOS —
ErrorExtension.swiftOnly
WKErrorDomainwith code8is mapped toexclude-credentials-match:https://github.com/corbado/flutter-passkeys/blob/main/packages/passkeys/passkeys_darwin/darwin/Classes/ErrorExtension.swift
The native
ASAuthorizationErrordomain with code1006(matchedExcludedCredential) is not handled.Android —
MessageHandler.javaThe existing check matches the error message:
However, when the error comes as
TYPE_CREATE_PUBLIC_KEY_CREDENTIAL_DOM_EXCEPTIONwith sub-typeTYPE_INVALID_STATE_ERROR, it appears to be caught by a different branch and classified asandroid-unhandledbefore reaching this check.Suggested Fix
iOS
Add a condition for the
ASAuthorizationErrordomain inErrorExtension.swift:Android
Ensure that
TYPE_INVALID_STATE_ERRORwith the excluded credentials message is also mapped toexclude-credentials-match.Environment
2.18.0