-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using CredentialsContainer.get() instead of Payment Request API #56
Comments
I am not aware of any clear benefits of using the Payment Request API over the Credential Management API, but I'm also not aware of clear benefits of using the Credential Management API over the Payment Request API :D. In either case, we need to bring together payment information and authentication information. As you note, in the initial proposal (and in what we implemented and trialed in Chromium), we brought authentication information into Payment Request. We did this because it was the Web Payments team that was working on this API, not the folks who are involved with the Credential Management API. Do you see a clear benefit to using the Credential Management API? (cc @equalsJeffH @mikewest ) |
At the moment I cannot really point out any clear technical benefits of using CM API over PR API. However, I think the SPC is closer conceptually to CM API than it is to PR API, especially if we also consider enrollment of the payment instrument as well. Credential Management API provides a way for the website to store/create and retrieve the different types of credentials via the convenient API. When we consider SPC it's also about storing and retrieving the credentials of a specific type. CM API provides abstract classes and interfaces that are extended to support the specific types of credentials e.g. password or public key. I can imagine SPC extending the CM API to allow the client to provide SPC-specific parameters to both create and retrieve the SPC-specific credentials. If we'd decide to use PR API to trigger retrieval of the SPC Credentials we still need to consider how to create/store the credentials in the user-agent. If I'm not mistaken the initial proposal actually suggests using Credential Management API to do so. Therefore, why not use Credential Management API also for storing/creating the credentials? |
The purpose of using the Payment Request API is that this provides a structured data object with the transaction details. It's natural for a developer to request a payment via a payment API, where SPC is part of that flow. Admittedly it might be the only required part of that flow but it is also possible that the flow includes invocation of a Payment Handler or prompting the user to select between multiple payment instruments that match the conditions provided in the request. |
I agree with @adrianhopebailie: use a payments-focused API for payments. |
OK. It seems people favor Payment APIs over Credential Management APIs. I think it's difficult to construct objective arguments, so this is based on preferences. Good to have a discussion anyways! |
@tblachowicz I wouldn't say it's just personal preference. By using payment specific APIs we solve a lot of privacy challenges for the browser. When a website invokes a payment API (as opposed to a general purpose API) then the browser can assume the context is a payment and can do things like show payment specific UI that would expose malicious websites that attempt to use the API for non-payment uses cases (tracking or farming data). |
Labeled after-v1 based on 3 March 2022 WG discussion https://www.w3.org/2022/03/03-wpwg-minutes |
Hey folks, The following is a proposal as to what moving to BackgroundSecure Payment Confirmation currently uses PaymentRequest as its API entry point: // On, e.g., merchant.com
const request = new PaymentRequest([{
supportedMethods: 'secure-payment-confirmation',
data: {
credentialIds: [ … ],
rpId: 'bank.com',
challenge: ...,
instrument: {
displayName: 'Fancy Card ****1234',
icon: 'https://fancybank.com/card-art.png',
},
payeeName: 'Merchant Shop',
payeeOrigin: 'https://merchant.com',
timeout: 360000,
}],
{
total: {
label: 'Total',
amount: { currency: 'USD', value: '5.00' }
}
});
try {
const response = await request.show();
await response.complete('success');
// response.data is a PublicKeyCredential, with a clientDataJSON
// that contains the transaction data for verification by the
// issuing bank.
} catch (e) {
// Handle SPC cancellation/failure, e.g. by presenting an
// alternative authentication method.
} This was done for a few reasons that I am aware of:
However, using PaymentRequest for SPC also comes with downsides:
The ProposalMove SPC to be called by web developers via navigator.credentials.get(). This is largely straight-forward as SPC already defines an internal WebAuthn extension. We would expose that extension and let developers use it directly instead of via PaymentRequest: // On, e.g., merchant.com
navigator.credentials.get({
publicKey: {
allowCredentials: [...],
rpId: 'bank.com',
challenge: ...,
timeout: 360000,
extensions: {
payment: {
payeeName: 'Merchant Shop',
payeeOrigin: 'https://merchant.com',
total: {
currency: 'USD',
amount: '5.00',
},
instrument: {
displayName: 'Fancy Card ****1234',
icon: 'https://fancybank.com/card-art.png',
},
},
},
}
}); There are two changes from the AuthenticationExtensionsPaymentInputs as currently specified in SPC: the Pros / Cons(A possibly incomplete list!) Pros:
Cons:
Fallback Behavior // Feature DetectionA strange consequence of moving SPC into a 'public' WebAuthn extension is that - unlike other WebAuthn extensions - the fallback behavior in a non-supporting browser can be actively undesirable for the calling website. Instead of rejecting the get() call, a non-supporting browser will ignore the payment extension entirely and show a normal WebAuthn experience to the user, producing a WebAuthn cryptogram. However if the caller requires payment details in the cryptogram, this cryptogram is useless to them and the user's time has been wasted! Note: this only happens in the '1p' SPC case, where the current origin is also the Relying Party. In the '3p' SPC case, the get() call immediately rejects in a non-supporting browser as the rpId will mismatch. However the '1p' SPC case is still of significant importance! To address this, we propose introducing a static method on PublicKeyCredential to indicate support (or lack thereof) for SPC: partial interface PublicKeyCredential {
static Promise<boolean> isSecurePaymentConfirmationAvailable();
}; This is very similar to the proposal in #81 already for PaymentRequest. It is also similar to the existing methods for detecting support for a user-verifying platform authenticator or for conditional mediation. SummaryIn summary, we think it would be feasible to move to We would be interested in discussing this at the Working Group, but most interested in hearing from developers who have already or are currently experimenting with SPC to see how much the API shape impacts them! |
cc @dcrousso |
Thanks, @stephenmcgruer. I would add as a "pro" that not having to also implement Payment Request API could make SPC much easier for browser makers to implement. |
Thanks for a great writeup Stephen. You raise some very valid points. This is a very important discussion that will have long term implications. There's an innate difference between a Transaction/Payment and a 'Login'. A classic login gives access to a set of 'scopes' on an account to view some fields and potentially to change things (but typically not without separate consent). A payment is an specific event that fundamentally alters your account (you have less money in your account). Fraud patterns and attacks are different, and how customers need to understand the difference between the two are different as well. I believe that most of the Fido/WebAuthn community see the real focus for WebAuthn as solving the 'login-problem'/getting rid of passwords. In fact, @timcappalli yesterday posted over on WebAuthn re-iterating that view: w3c/webauthn#1823 (comment) The second reality that we have to face is that the international payment community, and regulations around payments are focusing a lot on enabling customers with lower friction options. The Europe+UK mandates SCA (Strong Customer Authentication), but there are many exceptions allowed, e.g. Risk based or low value transactions, where SCA is not needed. The rest of the world also needs payments but does not require SCA. For most transactions however we still want a consistent and trusted customer consent (e.g. confirming a low value transaction amount), even if the strong auth component for Fido is not required. We are seeing merchants and card associations press for lower friction flows during transactions, and for this to be adopted, we need to define strategies that will allow these options and reduce the steps required. The Login problem is front and center in the design of WebAuthn; not payments. And there is not a payment focused community contributing there to provide input/directly shaping the API's. With a specific payment (or event) focused API, we can accommodate changes direclty and ensure that this API delivers to industry requirements. Tough call indeed. At this stage, I'm leaning towards rather seeing if we cannot simplify PaymentRequest/Secure Payment Confirmation invocation; keeping the payments focus, rather than blending it with Login. It can still be intrinsically linked to Fido for the 'step-up' / High trust use-case as authenticator and make that linking easy. That will allow the SPC use-case and interface to be driven by the payment community, based on best practices, industry feedback and regulation whereby SPC can be adjusted to deliver for better outcomes for payments (high success rates and low fraud). Would be interested to hear other perspectives too. |
I'm strongly in favour of the proposal from @stephenmcgruer In my previous comments I have been strongly in favour of "a payment API for payments" so I am sympathetic to @Goosth argument but I think the current implementation of SPC in PR API is the worst of both worlds. PR API was always intended to kick off a payment flow facilitated by the browser and SPC was intended to be one way to do auth inside that flow (not replace that flow). I still think invoking SPC from within a Payment Handler context warrants further exploration for example. To address some of the challenges:
The common use case for this primitive is to authenticate a user by getting the user to sign an RP-generated challenge with a known key and then assuming this proves that the current user is the same one that the key was provisioned for. I.e. The usefulness of this API for the AuthN use case depends entirely on how key provisioning is done and how the RP authNs users during that process. SPC is a new use case for the same basic primitive, except in this case:
TL;DR: I don't believe that using the Credentials API makes SPC an 'authentication' thing, it is explicitly invoked via a "payment" extension to a
Personally, I think the same should be used for light-weight transaction signing use cases too where the 'allowedCredentials` could include keys provisioned using WebCrypto and not platform authenticators. This would allow the browser to select the lowest friction signing ceremony based on the keys the RP has said it will allow for the current transaction. Or, an entirely new credential type could be defined which takes the same input as the PublicKeyCredential payment extension but is also provisioned and exercised via the Credentials API.
Seems like a poor reason to not deliver a better API. Priority of constituents etc.
We have always been told that SPC as a payment method in PR API as a temporary thing. I'd be pretty disappointed if "churn" was the excuse for not fixing the current SPC API.
Feature detection seems like a perfectly good solution to this issue. Could we also make feature detection possible by simply defining a new interface/dictionary for the input to the API? E.g. Something like: [SecureContext, Exposed=(Window)]
interface PublicKeyCredentialPaymentExtension {
[Default] object toJSON();
readonly attribute DOMString payeeName;
readonly attribute DOMString payeeOrigin;
readonly attribute PaymentCurrencyAmount total;
readonly attribute PaymentInstrumentDisplay instrument;
}; I think that would allow a simple: const spcSupported = ("PublicKeyCredentialPaymentExtension" in window); Finally, I mentioned previously in this issue that we should have use case specific APIs to assist the browser with context. I think this API as proposed by @stephenmcgruer still adheres to that. It's easy to tell if this is a login or a payment context and browsers can apply this heuristic in how they handle each case when evaluating privacy and security concerns. |
The initial proposal assumed that Payment Request API (PR API) should be used to trigger the SPC flow. The client code would use PR API providing the payment method as predefined value e.g. "secure-payment-confirmation" and the necessary parameters such as total amount, cryptographic nonce, fallback URL, and so on.
Alternatively, the same SPC flow could be triggered simply by invoking the Credential Management API CredentialsContianer.get() method as it happens for other types of credentials. Example SPRC request:
Similarly, the SPCCredential or PaymentCredential would extend the Credential interface to be consistent with the Credential Management API.
Are there any clear benefits of using Payment Request API instead of Credential Management API?
The text was updated successfully, but these errors were encountered: