-
Notifications
You must be signed in to change notification settings - Fork 42
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
Use PaymentRequest and PaymentResponse #99
Comments
In discussions we have concluded that we prefer to send a subset of what is found in the payment request. We discussed this in issue #2: If a merchant accepts 10 payment methods and the payment app only supports one of them, it is not a good use of resources to send the information about the 9 other payment methods to the app. Ian |
That's not a call for us to make. It's for the developer to make that call. I strongly disagree with this, and would like to see go to the TAG. |
Could you explain why this is an architectural issue? We had several reasons for subsetting the payment request, including privacy (for merchants) and performance. Ian |
I'm not clear on how a developer could make this call. FWIW, I also don't think there is any reason to send a bunch of other information about other payment apps to another payment app. |
Ok, I will do that, but please re-read: https://extensiblewebmanifesto.org in the mean time. The issue is that the spec defines new primitives, when there are already perfectly good ones we can use. And I quote: "By focusing on standardizing new low-level capabilities, and building new features in terms of them, we:
The rest is directly covered by the extensible web manifesto. Again, I don't want to quote the whole thing to you: just please read it, and substitute "PaymentRequest and PaymentResponse" where appropriate.
I don't see how including the PaymentRequest is a privacy issue. And where it is, we should address it. Being lazy and sending back objects is not the right approach.
You can't be serious 😳!? No one has implemented this yet, so I don't see how we can magically guess at performance characteristic - that sounds like "alternative facts". Premature optimization is the root of all evil. And look: if a service worker can handle potentially hundred of network "fetch" events, which have Request object just a complex as those in this API, while also reaching into the Cache database, etc., then a few payment requests are hardly going to be a problem. |
I'm absolutely not proposing we would do that. I'm just proposing we use the PaymentRequest/PaymentResponse primitives in the service workers. |
Ah, then I might have misunderstood based on the admittedly short discussion thus far. 😃 |
My bad for not being clear, I'll add an example to the OP of what I mean. |
Actually i think you are. The PaymentRequest object contains all of the method specific data for all payment methods accepted by a website. It contains information that the merchant may not have intended any app except one that is permitted by the payment method to receive. Example: Bobpay.com can declare in it's manifest that only the Bobpay app can process payment requests for the payment method bobpay.com. Fred installs a new payment app called OtherPay which supports basic-card payments. Fred visits a website that supports bobpay.com and basic-card payments. The payment request that is passed to the browser contains the bobpay.com payment method details including a merchant identifier etc. Fred chooses to pay with OtherPay (he's never even heard of bobpay.com) so the request is passed to the OtherPay app which sees the bobpay.com data and stores this in it's competitor analysis system. Yay free competitor information! This is the crux of #2 which provides good background to why the group took this decision. |
@adrianhopebailie, please see #96 (comment) There, we could just use the same mechanism for |
Actually, for canmakepayment, we can keep it simpler... we could have addressed this better if |
Thanks. Can describe what the event looks like that is passed to the event handler? I think you are suggesting it the same sequence of PaymentMethodData dictionaries that was passed in to the PaymentRequest constructor but with any that have no matching method stripped out. Is that right? |
On 25 Jan 2017, at 6:38 pm, Adrian Hope-Bailie ***@***.***> wrote:
@adrianhopebailie, please see #96 (comment)
Thanks. Can describe what the event looks like that is passed to the event handler? I think you are suggesting it the same sequence of PaymentMethodData dictionaries that was passed in to the PaymentRequest constructor but with any that have no matching method stripped out. Is that right?
Slightly out of date now, but:
https://marcoscaceres.github.io/payment-request-handler/#canmakepaymentevent-interface
But yes, it would have the PaymentMethodData - not the strings.... that's a mistake on my part.
… —
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
I think they are conceptually different.
Regardless they could implement some common interfaces. |
This issue as phrased is focusing on syntax, but I think the real disconnect here is dealing with the role of the browser, and syntax is simply being used as a proxy for that issue. For example, @marcoscaceres' explanation of this issue elsewhere includes an assertion that the web app should be responsible for collecting shipping address information, and the means of doing so are tied to the objects being identical on the Payment Request and Payment App sides of things. This proposal is wrong from a privacy perspective. The notion of how to design systems that preserve privacy is providing information only to those parties who need the information to do their jobs, and withholding it from all others. This proposal violates that principle. It is quite possible that I, as a user, would not like my bank to know who I'm shipping gifts to, and they have no need to possess this information to perform their task. Moreover, if I'm using a Bitcoin app to provide my payment, and the key value proposition of that Bitcoin app is that it has little to no personal information about me, giving it my full name and shipping address defeats its purpose pretty much entirely. |
You are exactly right. As I'm sure you are aware, autofill has already shown to be deficient in browsers from a privacy perspective - and probably can't be changed without breaking the Web: it does exactly as you describe, it unwittingly leaks data without user consent. My proposed solution gives more control to users by:
Then the user doesn't need to provide it to the payment app. That information can be provided to the merchant directly. That's what autofill is for. Additionally, just because a merchant says they need your address, doesn't mean the user should trust them (and the browser shouldn't just be giving it out without the consent of the user - which, in my model, is negotiated between the user and the payment app through the payment app's UI).
Again, the user is not obliged to provide this information to the payment app. The point is to put the user in control: if the payment app fails to provide the requested information (e.g., shipping address, name, etc.) to the merchant, then the merchant can get that information autofilled by the browser. Or, failing that, the user types that information manually into the merchant's site. |
@adrianhopebailie wrote:
I'd like us to investigate then using Web Crypto to solve this problem. I'm going to see if I can use your example:
Ok.
Ok.
But BobPay was never authorized to handle payments by the user - so it can't be used to make payments. As such, it doesn't enter the equation here, right? A user cannot choose a payment method they never authorized. So, to continue, let's pretend that Fred did register BobPay. And let's make it part of merchant.com's
Ok, let's pretend a merchant identifier is passed for argument's sake. Couldn't the payment method details and the merchant identifier (i.e.,
Ok.
But if the
Be nice to work through the above with real code.... diagramming it out... be right back. |
Ok, here is a very rough sketch. I need @hhalpin to help me a little here... or at least to sanity check. async function encryptData(url, data) {
// Note: with foreign fetch, this is an immediate response, as it would be cached.
const bobPublicKey = await fetch(url).then(r => r.text());
// I don't know what AlgorithmIdentifier to use 🤷♀️, Harry! HELP!!! ❤️
const cryptoKey = await crypto.subtle
.importKey("spki", bobPublicKey, algoIdentifier, false, ["encrypt"]);
const encoder = new TextEncoder('utf-8');
const clearData = encoder.encode(JSON.stringify(bobPayData));
// I have no idea if the below is correct... I stole it from the Web Crypto spec.
const aesAlgorithmEncrypt = {
name: "AES-GCM",
iv: crypto.getRandomValues(new Uint8Array(16))
};
return await crypto.subtle.encrypt(aesAlgorithmEncrypt, cryptoKey, [clearData]))
}
async function requestPayment() {
const bobPayData = {
merchantIdentifier: "XXXX",
bobPaySpecificField: true
};
const bobKeyURL = "https://bobpay.com/public.key";
const methodData = [{
supportedMethods: ["basic-card"],
data: {
supportedNetworks: ['aFamousBrand', 'aDebitNetwork'],
supportedTypes: ['debit']
}
}, {
supportedMethods: ["bobpay.com"],
data: await encryptData(bobKeyURL, bobPayData),
}];
const request = new PaymentRequest(methodData, details, options);
if (await request.canMakePayment() === false) {
return; // Too bad... do something else
}
const paymentResponse = await request.show();
} |
Was talking to @martinthomson about this, and he proposed that this could alternative be solved by adding an "origin" member to the That way, the browser knows where to route the events to only one specific origin - and only if that origin is registered. So: {
supportedMethods: ["bobpay.com"],
data: {
merchantIdentifier: "XXXX",
bobPaySpecificField: true
},
origin: "https://bobpay.com",
} Will only ever go to |
@marcoscaceres -- if you're willing to bind payment methods to origins so tightly, then we don't need an API at all here. What you've described is the way web payments work today. What you've described is what we're trying to fix. |
@adamroach I respectfully disagree. There is no mechanism today to wake up a service worker to perform a payment without spinning up a browser window. There is also no mechanism for the browser to spin up a "payment window/overlay" that is bound to the a browser tab. This API solves both those problems too. In the examples above show multiple ways of addressing the problem that continue to allow the API to function as intended while meeting the privacy requirements of not leaking data. |
@adamroach, to be clear, the "origin" is optional above - and would be for those who want to have a 1-to-1 relationship ("bobpay.com" === "exclusively registered https://bobpay.com"). And it saves the hassle of having to use web crypto. And, you could still have multiple registered payment handlers of "Bitcoin", for instance: bad-actor.com and goodbitcoin.com. Using the web crypto approach, "bad-actor.com" would not be able to decrypt "goodbitcoin.com"'s Lastly, we can assure that the standardized payment methods (e.g., basic-card) should not have leaky |
Per my understanding, it's the payment method author that is in charge of deciding which handlers ("payment apps") should be able to see data associated with a particular payment method. Why should we burden merchants with having to fetch this information and specify it in the request instead of having the browser do it for them? If we're ok with having the browser use an |
I'm not following, sorry :( What is the "payment method author"? A payment app (evil.com) can only say: "I support 'BobPay', send those my way!". It can lie all it wants, but merchant.com can protect itself by always making sure that 'BobPay' requests only ever go to 'bobpay.com'.
Because, as I understand it, it is merchants, in coordination with payment processors, that need to include privacy-sensitive/proprietary/merchant-identifiying information in the
Again, I'm not sure I am fully understanding, but - if merchant says "I support 'basic-card', but not Amex!" - then The original requirements haven't changed: the problem is just being potentially solved differently. Again, let's please start using code to reduce ambiguity. |
fixed some wording above. |
No problem. By "author" I meant the entity that is in control of the payment method -- either of its specification or of the manifest that lives at the end of the URL that identifies it. So, for example, someone (the author) invents "Floyd Bucks" that various websites can use and publishes a URL with information about this payment method. When this URL is fetched, it returns a document that includes a restricted list of origins that may provide payment apps for it. Then, when a payment app tries to say that it supports this payment method in the browser, this URL will be fetched and checked to ensure that they are allowed to do so. Note that, as I mentioned elsewhere, a "payment method", in this WG, is understood to refer to a set of rules and potentially a network for processing payments. It is not a "payment instrument" or "payment credential" like a credit card. These are merely examples of mechanisms for authenticating on a payment network. We are trying to enable the creation and interoperability of multiple payment methods on the Web. Anyone should be able to create a payment method, and if they so choose, restrict which origins may provide applications to implement that payment method.
See above. One idea that has been thrown about here by the WG is to have the payment method manifest specify which apps/origins may support it -- and payment mediators (e.g. browsers) would enforce this.
The merchant doesn't care which app you use to process the payment. It cares which payment method you use. The apps that are permitted to use this payment method are decided by the payment method author -- which is an abstraction level away from the merchant. We are trying to enable the independent creation and management of payment methods -- so that merchants may use them at will with any end user that has any app that supports (and is permitted to use) that payment method. We don't want the merchant to have to concern themselves with which app you are using (or to unduly restrict you).
That's fine, but I think there's a basic terminology issue. A credit card is not "payment method", it's a "payment credential" or "payment instrument". When writing code, we'd simply be reusing the same terms that are causing confusion. I'm concerned these are being conflated -- and the abstraction we're trying to introduce where payment methods are independently crafted and are what merchants and end users agree on (not apps) is being lost. |
@marcoscaceres wrote, "adding an "origin" member to the PaymentMethodData, that bounds the method to the origin that must be registered to receive the event." For proprietary payment methods, we have begun to specify something that allows the payment method owner to control which apps can support the payment method. In effect, that provides a guarantee enforced by the browser that payment requests will only go to those apps (or origins): (There are other bits in that proposal involving digital signatures of specific apps, for added security.) |
This can just as easily be done by the browser.
I'm not sure how this is of benefit. I'm certain users will be frustrated by the notion that the address they already have on file with bobpay.com needs to be re-entered for alicepay.com.
Foreign nationals like myself? ;) So, in terms of who I would trust with sensitive personal data in the face of state-level attackers, I'd trust browser data sync mechanisms far more than payment providers (Global Payments, Chase, Citibank, Heartland) or merchants (Target, Home Depot). The reason is because those entities necessarily store information in a form that the institution can use, which means the institution can necessarily decrypt the information (if they do, in fact, store it encrypted at all, which is far from given). Browsers, on the other hand, have the option of storing data as opaque information that the sync service could not decrypt, even under sophisticated attack or court order. See, for example, the way Firefox handles sync data, keeping in mind that the kind of data we're talking about here is what that document refers to as "class-B data" (roughly: the class of data that Mozilla couldn't retrieve no matter how badly it wanted to). The proof here is in the pudding: despite a number of high-profile attacks on top banks and top merchants, as I cite above, there has been no breach of browser sync data, even though it would easily be several times more valuable. I can't speak to what other browsers do; but in Firefox's case, at least, this is because such exploits are basically impossible. So, if you're weighing the relative safety of browser sync mechanisms against the data security practices at financial institutions and merchants, you've got it exactly backwards.
We've had extensive discussions in the WebPayments working group as a whole about the suitability of form fill and form autofill for this purpose. The strong -- and maybe unanimous (I can't recall) -- consensus was that it was inadequate for this purpose, and that we needed something more tightly bound to the checkout flow. Merchants were among the most vocal on this topic, implying that this was a large part of the value they see in the Payment Request API. So, I'll reiterate my earlier point: you're pushing to re-use existing web technologies that simply don't meet the needs of the problem. If we take on autofill as the solution here, there's a very real risk that the value of this API to merchants will be sufficiently diminished that they simply opt not to use it. You'll have a set of documents that you personally think are more perfect in some dogmatic way, but which are effectively dead on arrival because they don't do what their audience has demanded they do.
I would certainly expect browsers to give users full agency over whether this information, when requested, is actually provided to merchants. I'll also note that your proposal, as you describe it, has a pretty big Achilles' heel in this respect: just as the payment app can elect to negotiate between itself and the user whether to provide this data, it can also elect to provide it without any user approval at all.
Which, as I say above, is exactly what merchants want to avoid. |
Based on the Payment Apps TF call yesterday I believe there to be two issues under discussion here and we should separate them:
Regarding issue 1, as @adamroach points out, this was debated at length within the WG right at the beginning of our work. See: w3c/webpayments#72 The resolution of the WG was to integrate collection of this data into the API. @marcoscaceres , as an editor of the PR spec I think your best course of action if you think this should change is engage your fellow editors directly and come back to the group with a proposal that the editors all agree on. Regarding 2, it is difficult to see how the current The same goes for the //From https://w3c.github.io/browser-payment-api/#paymentrequest-interface
[Constructor(sequence<PaymentMethodData> methodData, PaymentDetails details, optional PaymentOptions options),
SecureContext]
interface PaymentRequest : EventTarget {
Promise<PaymentResponse> show();
Promise<void> abort();
Promise<boolean> canMakePayment();
readonly attribute DOMString? paymentRequestID;
readonly attribute PaymentAddress? shippingAddress;
readonly attribute DOMString? shippingOption;
readonly attribute PaymentShippingType? shippingType;
attribute EventHandler onshippingaddresschange;
attribute EventHandler onshippingoptionchange;
};
[SecureContext]
interface PaymentResponse {
serializer = {attribute};
readonly attribute DOMString paymentRequestID;
readonly attribute DOMString methodName;
readonly attribute object details;
readonly attribute PaymentAddress? shippingAddress;
readonly attribute DOMString? shippingOption;
readonly attribute DOMString? payerName;
readonly attribute DOMString? payerEmail;
readonly attribute DOMString? payerPhone;
Promise<void> complete(optional PaymentComplete result = "unknown");
}; The current API shape is partly a result of the resolution the group took to capture shipping data and partly a result of discussion around making the API more compose-able. There were strong advocates for a more compose-able API that separated the PaymentRequest from other, non-payment, stuff. See: w3c/webpayments#39 The strongest proponents for the current structure were @zkoch and @adrianba who at the time were the editors of the PR spec. @marcoscaceres , again, if you want to change the shape of the API then I suggest discussing this with your fellow editors first. I don't think it is useful for the group to debate this any further while the editors and implementors are not in agreement. For example, taking inspiration from @dlongley 's proposal, if there was a I suggest we close this issue and allow the editors of Payment Request to decide how they wish to proceed with that spec and on that basis we can decide if there is a need to make changes to the Payment Apps spec. |
At today's payment apps call [1] we resolved to close this issue as follows:
AdamR took an action to submit a pull request to the payment app api spec to update the |
Sounds good. Looking forward to seeing those new interfaces. |
So, I've gone over the current API. With yesterday's decision not to pass along payment details (see #91), it no longer makes sense to change "total" to "details", so it's staying as-is. I will be adding an "id" that matches "id" in the PaymentRequest. Based on the current definition of PaymentRequest, however, no other changes seem to make sense; so, in practice, this ends up being a very simple delta. |
Closing this issue since relevant changes have been merged. |
The API should use the
PaymentRequest
andPaymentResponse
to the fullest, and not invent new things.It should work the same as "fetch" event handler in ServiceWorkers.
The text was updated successfully, but these errors were encountered: