webauthn icon indicating copy to clipboard operation
webauthn copied to clipboard

Clarify how to differentiate between exceptions

Open dolda2000 opened this issue 2 years ago • 9 comments

Proposed Change

As far as I have been able to tell, exceptions from the WebAuthn UI interactions fall into three general categories, that are fairly important to distinguish:

  1. Totally normal exceptions that the user initiated and is aware of. An example would be the user simply cancelling the interaction. The user is well aware of what happened and doesn't need to (shouldn't, in fact) be further informed of it.
  2. Semi-normal abortions of the UI, that happened because of user interaction, but where the user may not know exactly what happened and should be informed of it. An example would be that, on Firefox, if the user uses an authenticator that doesn't contain any of the credentials among allowCredentials, Firefox simply closes the UI and returns this fact to the RP as an exception. The user might not be aware that he used the wrong authenticator and should be told about it. (Interestingly this seems to be different on Chrome, where the UI directly informs the user of this fact and offers to retry or cancel.)
  3. Actual exceptional conditions where the RP did something wrong. An example would be providing malformed or otherwise invalid options objects. In this case, the RP should be able to tell the user that something unexpected happened and to perhaps contact support if the problem persists.

However, I cannot find anything in the spec about how to make these distinctions, and neither have I been able to infer anything from actually observed exceptions. Exceptions that fall into different categories seem to commonly use the same error name, leaving only the exception message to infer anything from, but they are apparently primarily intended to be human-readable, localizable, and differ between different browsers.

I am currently just relying on Chrome's behavior to directly tell the user of various aborting conditions (which is nice) and the complete and entire bug-freeness of my site, but obviously neither of those are particularly functional assumptions, and in fact on Firefox several interactions are quite suboptimal, so I'd really appreciate some clarity on the issue.

dolda2000 avatar Feb 24 '23 22:02 dolda2000

You have to go digging into the spec to connect the pieces, but the spec definitely outlines discrete error scenarios that should be reliably detectable. For sake of discussion, I've done so with my own library for both registration and authentication:

  • https://github.com/MasterKale/SimpleWebAuthn/blob/master/packages/browser/src/helpers/identifyRegistrationError.ts
  • https://github.com/MasterKale/SimpleWebAuthn/blob/master/packages/browser/src/helpers/identifyAuthenticationError.ts

The exceptions here are the various NotAllowedError that can come up. The spec defines a couple of discrete conditions under which NotAllowedError can be mapped to specific error causes. However, browsers have overloaded this type of error with browser-specific error messages too that make it trickier to differentiate spec-related error conditions from browser-related error conditions.

All this said, I agree that the spec doesn't make it easy at all to identify all the discrete errors that can come up during a WebAuthn ceremony. Perhaps this becomes an editorial PR to bundle these errors together and under what conditions they'd arise.

MasterKale avatar Feb 24 '23 22:02 MasterKale

Please correct me if I'm wrong, but the code you link to seems to be more about providing some explanatory text for every error, rather than, for example, categorizing errors into those that should be displayed to the user vs those that shouldn't, no? As far as I can tell, it also does not seem to provide a useful return value when, for example, Firefox throws an error in the above mentioned example where the presented authenticator doesn't contain a key for the account.

dolda2000 avatar Apr 16 '23 19:04 dolda2000

2023-08-30 meeting: @MasterKale did you still want to do anything with this issue for L3?

timcappalli avatar Aug 30 '23 18:08 timcappalli

From 11/1/23 WG meeting: There's definitely still a desire for this from RP's, CC'ing @nsatragno and @emlun to consider the idea that came up today about being able to include more info in errors that happen after a user consents to a ceremony.

MasterKale avatar Nov 01 '23 20:11 MasterKale

Just noting that there is precedent in the spec for this: the InvalidStateError in create() explicitly calls out that a more granular error is acceptable because the user has consented to the operation:

Note: This error status is handled separately because [...] and the user has consented to the operation. Given this explicit consent, it is acceptable for this case to be distinguishable to the Relying Party.

I too was recently surprised that we don't have such a case in get() for when the user attempts to use an authenticator that is not registered. There are probably other error causes that could be communicated too ("various failure cases in the hybrid flow" was mentioned on the call). We might end up needing a custom DOMException derived interface for that.

emlun avatar Nov 01 '23 20:11 emlun

Another error use case to consider:

  • RP requires UV, but a user tries to use a U2F security key that doesn't support PIN. It would be useful to see that the user tried to use an older security key so we could be more specific about why they couldn't use it.

MasterKale avatar Nov 03 '23 19:11 MasterKale

I'd also love for it to be clarified how the RP can interpret InvalidStateError during create(…):

  • https://github.com/w3c/webauthn/issues/1566
  • https://github.com/w3c/webauthn/issues/1888

For now the only possible cause is a excludeCredentials match, but I believe the spec does not specify that this is a safe assumption for the future.

lgarron avatar Nov 03 '23 20:11 lgarron

I see in the spec InvalidStateError is returned when the credential is in the excludelist in the registration ceremony. Firefox, Chrome, and Edge return this same error when you try to re-register the same authenticator but I wasn't able to find this in the spec. Can we say the later is a safe assumption? If so, how do we differentiate between the two exceptions?

sameadis avatar Jan 23 '24 15:01 sameadis

@sameadis I believe what you are describing is two ways to say the same thing? Namely that "the credential is in the excludelist" is precisely the way the client and authenticator detect that you "try to re-register the same authenticator", so these are the same one exception, not two different cases.

emlun avatar Jan 24 '24 10:01 emlun