I’m trying to implement a FIDO onboarding application for an app. To create the user credentials with WebAuthn API I use:
navigator.credentials.create(options)
This return a promise that resolves with user credentials when allowed. However, if instead of allowing, the user cancel the credentials creation, then a DOMException
with with name NotAllowedError
is thrown.
In the app, the credentials creation call to the Web Authentication API is triggered when the user clicks a button, that has an onClick which points to a function that also toggles a loading animation before attempting to create the credentials. In order to provide a good user experience, when the user clicks to cancel, I want to handle this exception, toggle the loading animation off and then display the button to create credentials again.
I want to know the best practices when handling this scenario. I don’t know enough about this flow to even know if it’s safe to wrap the call in a try-catch then handle every error with the name of NotAllowedError
or if this Error is also thrown in other scenarios, for example, when failing to contact the user device, which in this case could cause the user that actually does want to allow credentials creation to be trapped in an infinite loop of clicking to create credentials, clicking allow, getting a NotAllowedError, having the button to create credentials displayed over again.
try {
const credentials = await navigator.credentials.create(options)
// do whatever
} catch (err) {
if (err instanceof DOMException && err.name === "NotAllowedError") {
// handle user cancelation
return
}
// handle other scenarios
}
Long story short, I want to handle this scenario of user cancellation specifically and any other scenario I would handle the error some other way.
2
Answers
NotAllowedError
is returned in a number of situations, but they’re all broadly that the user abandoned the WebAuthn UI. The only other meaningful error for creation isInvalidStateError
, which indicates that the user tried to create a credential on a platform authenticator which already has one of the credentials included in the exclude list.If your worry is that
NotAllowedError
might be returned synchronously, without user interaction, then that is possible. At least with Chromium, it can happen in cases such as when an already-inserted security key returns an invalid messageSince
NotAllowedError
can occur in various situations where the WebAuthn UI interaction is incomplete or incorrect, it is important to handle this error in a way that does not assume it is always a direct user cancellation.You might want to include a message to the user indicating that the credential creation process was not completed, rather than explicitly stating that they cancelled it.
As agl mentioned, handling
InvalidStateError
is also important.That error occurs when there is an attempt to create a credential that is already on the exclude list of the platform authenticator. That needs to be handled separately, possibly with a specific error message to the user.
In scenarios where
NotAllowedError
might be returned synchronously (e.g., due to an invalid message from an already-inserted security key), it is still reasonable to catch and handle this within the try-catch block.However, additional logging or a more detailed error message could be helpful for debugging and user information.
Your
createCredentials
function would be:That way, your error handling becomes more robust and takes into account the variety of scenarios that can lead to a
NotAllowedError
, as well as handlingInvalidStateError
specifically. That means a better user experience and aids in debugging and troubleshooting.