Hey folks; we've discussed this a few times, but I realized (thanks to Ian!) that I don't think we really have a clear issue outlining the ideas around more output states for SPC. So I put together some diagrams and wrote this up :).
Background / Motivation
We've heard feedback (repeatedly - this is nothing new!) that outside of the success case of SPC, it is difficult for integrators to know what has happened when SPC failed and how they should proceed. This largely stems from the WebAuthn privacy model (see spec) which states that we cannot allow sites to detect the difference between:
A user not having a given credential/passkey
A user having the credential but declining to use it
The goal of this privacy model is to stop sites from being able to track users via the existence of credentials.
In practice, this means that most of the non-success outcomes in SPC result in a single error - a NotAllowedError DOMException. The exception is the showOptOut OptOutError. The reason we can be specific for OptOutError is that it can be returned whether or not a credential matched - so there's no information leakage to the website upon receiving it.
(But of course see #274 for discussions around removing showOptOut entirely)
We can model the current output states as follows:
Or if it helps, here they are with Chrome's current UX:
In Chrome, we think there's a path here to give some additional information to SPC integrators, notably around distinguishing whether the user really wants to continue or wants to cancel this payment.
Proposal
Introduce a new output state for SPC, which represents an explicit user desire to cancel. For arguments sake, we'll use the AbortError DOMException for the rest of this proposal, but ultimately what error code we choose doesn't matter as long as its distinguishable.
In order to introduce this without causing a privacy issue, we will need to have it be possible to get this new AbortError from both the 'credentials matching' and 'credentials dont match' cases. To do this, we propose making SPC always display a transaction experience (spec link) to the user, and have the matching/non-matching of credentials instead influence whether the transaction UX is followed by a WebAuthn experience or not.
One could perhaps distinguish these into a "confirmation transaction UX" and a "verifying transaction UX" - the former only confirms the users intent to purchase or not, whilst the latter can additionally verify the users identity (expressed via a WebAuthn signing). In this proposal, we refer to the case without credentials as a "Fallback" experience.
The introduction of this new output state allows for the following user flows:
As noted in the diagram, the integrator should consider the outcomes of the show() call to mean the following:
Signed cryptogram returned - user wishes to proceed with payment and has verified their identity
NotAllowedError - user wishes to proceed with payment but either cannot OR does not want to use the passed-in credentials to do that
AbortError - user explicitly does not wish to continue with payment. Integrator should return to merchant checkout screen or handle otherwise sensibly.
OptOutError - as today, the user wishes for the RP to remove this credential (again, see #274 )
Open Questions
Feel free to propose your own!
Should cancelling WebAuthn at the OS dialog level (1) lead to the "wants to continue but can't do FIDO" outcome as in the diagram above, (2) lead to the "user cancelled" outcome, or (3) just return to the SPC transaction dialog without fully exiting from SPC?
Note: It may be that on certain platforms the browser cannot distinguish between WebAuthn cancel vs WebAuthn fail-to-verify
Should we raise an NotAllowedError or return a technically-successful outcome but which contains an indication that the user didn't actually perform any identification?
How would this change fit into 3DS and other such protocols that may already have specified SPC integrations?
Does using AbortError work? Should we add a new UserCancelled error?
Hey folks; we've discussed this a few times, but I realized (thanks to Ian!) that I don't think we really have a clear issue outlining the ideas around more output states for SPC. So I put together some diagrams and wrote this up :).
Background / Motivation
We've heard feedback (repeatedly - this is nothing new!) that outside of the success case of SPC, it is difficult for integrators to know what has happened when SPC failed and how they should proceed. This largely stems from the WebAuthn privacy model (see spec) which states that we cannot allow sites to detect the difference between:
The goal of this privacy model is to stop sites from being able to track users via the existence of credentials.
In practice, this means that most of the non-success outcomes in SPC result in a single error - a
NotAllowedError
DOMException. The exception is the showOptOutOptOutError
. The reason we can be specific forOptOutError
is that it can be returned whether or not a credential matched - so there's no information leakage to the website upon receiving it.(But of course see #274 for discussions around removing showOptOut entirely)
We can model the current output states as follows:
Or if it helps, here they are with Chrome's current UX:
In Chrome, we think there's a path here to give some additional information to SPC integrators, notably around distinguishing whether the user really wants to continue or wants to cancel this payment.
Proposal
Introduce a new output state for SPC, which represents an explicit user desire to cancel. For arguments sake, we'll use the
AbortError
DOMException for the rest of this proposal, but ultimately what error code we choose doesn't matter as long as its distinguishable.In order to introduce this without causing a privacy issue, we will need to have it be possible to get this new
AbortError
from both the 'credentials matching' and 'credentials dont match' cases. To do this, we propose making SPC always display a transaction experience (spec link) to the user, and have the matching/non-matching of credentials instead influence whether the transaction UX is followed by a WebAuthn experience or not.One could perhaps distinguish these into a "confirmation transaction UX" and a "verifying transaction UX" - the former only confirms the users intent to purchase or not, whilst the latter can additionally verify the users identity (expressed via a WebAuthn signing). In this proposal, we refer to the case without credentials as a "Fallback" experience.
The introduction of this new output state allows for the following user flows:
As noted in the diagram, the integrator should consider the outcomes of the
show()
call to mean the following:NotAllowedError
- user wishes to proceed with payment but either cannot OR does not want to use the passed-in credentials to do thatAbortError
- user explicitly does not wish to continue with payment. Integrator should return to merchant checkout screen or handle otherwise sensibly.OptOutError
- as today, the user wishes for the RP to remove this credential (again, see #274 )Open Questions
Feel free to propose your own!
NotAllowedError
or return a technically-successful outcome but which contains an indication that the user didn't actually perform any identification?AbortError
work? Should we add a newUserCancelled
error?