Skip to content
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

Letting the payment app decide between HTTP and Javascript communication #130

Closed
tommythorsen opened this issue May 18, 2016 · 32 comments
Closed

Comments

@tommythorsen
Copy link
Member

tommythorsen commented May 18, 2016

The current Payment Apps spec proposal suggests that communication between the user agent and the payment app is initiated by means of a POST, but discussions (for instance here) indicate that people are also positive to using a javascript method to pass the payment request to the payment app. For instance something like this:

//After the payment app loads ask the browser for the current request that it must process
var paymentRequest = navigator.payments.getRequest();

However, if we want to have the javascript getRequest() function above, then it does not seem very elegant to also pass the payment request object to the payment app by means of HTTP POST.

It was suggested in a mail thread that we could let the payment app itself decide whether to use HTTP or Javascript at the time of registration.

Håvard Molland said:

The method for sending the request to the payment app could be set in the app manifest, and this would make life easier for the browser payment app developers. I certainly don't agree that browser payments apps are corner cases.

@adrianhopebailie answered:

I certainly like the idea of supporting both and allowing the app to specify which integration it uses when it is registered. Adam Roach and Ian suggested to me that we consider something like the IdP registration in WebRTC so we'll see where we can weave that into the payment apps proposal.

I propose that we change the payment app spec proposal so that the decision of whether to use HTTP or Javascript is not based on the mime type of the payload returned from an HTTP POST, but that the decision is based on a property in the payment app manifest (or possibly some other registration-time mechanism).

@adrianhopebailie
Copy link
Collaborator

@tommythorsen can you submit a PR against the proposal that suggests how this might be done.

I like the idea of re-using the mechanism that is used in WebRTC to register an IdP service.
https://w3c.github.io/webrtc-pc/#sec.register-idp

Perhaps we need a PaymentApp interface that has a ProcessPaymentRequestCallback member that returns a Promise<PaymentResponse?

When the user calls register() to register the payment app they can pass in either a start_url or an implementation of PaymentApp.

@tommythorsen
Copy link
Member Author

@adrianhopebailie I'll make a PR

@tommythorsen
Copy link
Member Author

@adrianhopebailie
I added PR #131. It doesn't do the WebRTC IdP service registration thing, mostly because I'm completely unfamiliar with WebRTC, but also a little bit because a simple field in the manifest file is very straight-forward and easy to both understand and implement for everyone involved.

If you feel the IdP service registration method is way better, perhaps we can have a discussion on the advantages and disadvantages of each approach.

@adamroach
Copy link

The WebRTC IdP registration isn't persistent -- it's added to each RTCPeerConection object after it's created. So it's not exactly the model to look at. When I mentioned it as a potential model for the local portion of payment apps, I meant it more as a model for the communication channels.

All of that said, with the discussion of POST as a desired means for communication with payment apps, I think we might want to reconsider how this all works. I'm not terribly happy with having multiple ways to accomplish the same thing, since it makes implementation and testing of the system that many times harder.

So, if we're going down the POST path, I would suggest we contemplate using POST for all interactions, and describe how to use service workers to process such requests locally.

Note that this doesn't change how websites interact with the whole payment system at all -- these POSTs are generated by the mediator rather than by the web page anyway.

@adrianhopebailie
Copy link
Collaborator

The WebRTC IdP registration isn't persistent -- it's added to each RTCPeerConection object after it's created. So it's not exactly the model to look at. When I mentioned it as a potential model for the local portion of payment apps, I meant it more as a model for the communication channels.

That's true but it's a nice way for an "app" to install a piece of executable Javascript that can be run by the browser when required. I have an idea of how we could do something similar will try and put a PR together.

So, if we're going down the POST path, I would suggest we contemplate using POST for all interactions, and describe how to use service workers to process such requests locally.

I agree with this and only propose the JavaScript option as an addition. It never hurts to give developers choices.

In that respect, I think #131 is a more extreme change than we need. I don't think we should take out the existing behaviour but rather add other behaviour if the app chooses to use Javascript.

@tommythorsen
Copy link
Member Author

So, if we're going down the POST path, I would suggest we contemplate using POST for all interactions, and describe how to use service workers to process such requests locally.

I agree with this and only propose the JavaScript option as an addition. It never hurts to give developers choices.

In that respect, I think #131 is a more extreme change than we need. I don't think we should take out the existing behaviour but rather add other behaviour if the app chooses to use Javascript.

Are you proposing then, to still POST the serialized PaymentRequest to payment apps who only want to deal with javascript? Will these payment apps then ignore the POST'ed payment request and use navigator.payments.getRequest() instead? I feel that this is very inelegant, and that there isn't that much benefit to be had from doing it this way.

I do think there is a significant amount of payment apps that will strongly prefer javascript over POST for the simple reason that POST requires server-side scripting to process, whereas javascript can be done entirely client-side, which makes it possible for the payment app html to be served out as an entirely static page. This can be a great advantage for major payment providers, whose payment apps have to process large amounts of payments.

@adrianhopebailie
Copy link
Collaborator

Are you proposing then, to still POST the serialized PaymentRequest to payment apps who only want to deal with javascript?

No, but we should still allow apps that render HTML to do so in response to a POST and it looks like your change took that option away.

@adamroach
Copy link

@adrianhopebailie wrote:

It never hurts to give developers choices.

My point is that, yeah, it kinda does, since the browsers end up having to code for, test, and maintain two different codepaths.

@adamroach
Copy link

@tommythorsen wrote:

Will these payment apps then ignore the POST'ed payment request and use navigator.payments.getRequest() instead? I feel that this is very inelegant, and that there isn't that much benefit to be had from doing it this way.

No, they would call ServiceWorkerContainer.register(), which would cause the local payment app to be activated whenever an appropriately-scoped POST is called. The local payment app would then handle this POST response in the same way as a remote payment app does.

@tommythorsen
Copy link
Member Author

No, but we should still allow apps that render HTML to do so in response to a POST and it looks like your change took that option away.

My change did indeed take that option away, as I thought that was the direction we were heading. In what situations do you think this option is useful?

If an app wants to render HTML, then it does need to use javascript to pass the response back to the user agent. If the app uses javascript to pass the response back, is it really that unreasonable to require that they use javascript to get the payment request in the first place?

@adrianhopebailie
Copy link
Collaborator

@adamroach - I agree with you but I think we should prove that this is easy to do using ServiceWorkers before we dismiss offering an alternative.

I'm busy trying to hack together a POC of this and will share when I am done.

If the app uses javascript to pass the response back, is it really that unreasonable to require that they use javascript to get the payment request in the first place?

@tommythorsen - I'd say yes actually. If the processing of the payment request is complex then it might be preferable to do this server-side and to return an HTML UI with just light client-side processing (maybe just a confirmation page).

@jnormore
Copy link
Member

What's the advantage of requiring a getRequest call over just including it in the POST params in either case? The POST request to start_url happens in both cases, even if it's a static page with some javascript (mentioned above as a valid performance concern for some merchants) the payment app can handle the params in the client-side javascript rather than introducing a new way to communicate.

@adrianhopebailie
Copy link
Collaborator

@jnormore - I think that is what @adamroach is proposing.

I think we should test that approach before we decide we don't need a getRequest() though

@adrianhopebailie
Copy link
Collaborator

And... the one advantage of not sending via POST is that the browser doesn't need to serialize the PaymentRequest object into JSON first

@adamroach
Copy link

And... the one advantage of not sending via POST is that the browser doesn't need to serialize the PaymentRequest object into JSON first

Are you worried about performance or complexity here? I have a hard time imagining either one being an issue at all.

@adrianhopebailie
Copy link
Collaborator

As a non-browser-vendor I was speculating. i.e. Not needing to serialize feels like less work to do but if it doesn't save us anything then I guess that's not really a useful argument so scratch it 😄

@jnormore
Copy link
Member

Sorry @adamroach, missed your comment on that, in that case I agree with your proposal ;)

@tommythorsen
Copy link
Member Author

@adrianhopebailie

I'd say yes actually. If the processing of the payment request is complex then it might be preferable to do this server-side and to return an HTML UI with just light client-side processing (maybe just a confirmation page).

You could of course pass the payment request to the backend from javascript, for further processing. I'm not a web developer, but I believe this is a fairly common thing to do, as it lets the payment app display a nice progress UI while the backend performs complex, and possibly time-consuming, processing of the payment request.

@adamroach

No, they would call ServiceWorkerContainer.register(), which would cause the local payment app to be activated whenever an appropriately-scoped POST is called. The local payment app would then handle this POST response in the same way as a remote payment app does.

This seems promising, but I am unfortunately completely unfamiliar with service workers. I guess I have some reading up to do. If we could make a proof-of-concept to establish that this is a convenient way for payment app implementors to deal with POST requests, this might be the path forward.

@tommythorsen
Copy link
Member Author

@ianbjacobs: You said in a comment the PR that you would like to see how the spec looks like with my change, so I hacked together some php which will let you view the unmerged file here.

@tommythorsen
Copy link
Member Author

To elaborate a bit on my motivation for creating this issue (and the corresponding PR): I strongly prefer APIs (and specifications) that are simple and obvious. At some point, browser vendors (like myself) and payment providers are going to have to get their hands dirty and implement the things that we have specified. What are their reactions going to be? Will they say "Right, I get it! This is how it obviously should work", or will their reaction be "Wtf? Why do I have to do it this way? This makes no sense".

If we want this spec to be widely adopted, it would be beneficial to us if the specification prompts a reaction like the first of those two responses. But when I look at the HTTP POST with the subsequent switch on mime-type, I just fear that we're leaning towards triggering the latter response.

I've been looking into the service worker approach to intercepting POST messages today. The preliminary results are in the form of a modified version of the Visa Checkout based payment app I made earlier and is available here. The source code is available here. (Note that it doesn't actually parse the POST at the moment, but the rest of the communication between the web page and the service worker is in place. Also, the first time you navigate to the app you get a white page because the service worker isn't registered yet. Reload to get the proper app). It seems like this would be a working approach, but I wouldn't go so far as to call it convenient...

@ianbjacobs
Copy link
Contributor

@tommythorsen,

Thanks for writing up your thoughts and coding them as well.

I am thinking ahead to the face-to-face meeting in July. I think a demo would
help us through the conversation about which communication approach to take.

Ian

@cyberphone
Copy link

cyberphone commented May 20, 2016

HTTP POST has unlike a (properly defined) JS interface numerous of disadvantages including the lack of a merchant security context and handle to the calling window. It has one advantage though: The lack of a security context completely removes (possible) SOP issues from the equation :-)

@tommythorsen
Copy link
Member Author

@ianbjacobs

Demos are always useful. Unfortunately I won't be able to attend the face-to-face meeting in July.

@adamroach
Copy link

I know I've gone on record as saying that either approach is fine with me, as POST can be adapted to JS via service workers, and JS can be turned into POST with XHR; however, I've been looking more closely at how the interaction works, especially in the context of browser components and native apps, and have been increasingly finding POST to be an awkward fit.

So I'd like to throw my hat in with Tommy and Anders in favoring a JS approach over a POST one. At a high level: the URL pointing to the payment app would be expected to contain javascript. This JS is loaded into a windowless context. If it needs to display information to the user, it can use window.open() and load its UX into that window.

The payment request would be provided by the mediator via some a javascript affordance -- e.g., using window.postMessage() -- which could then be used to provide a response from the script.

@adrianhopebailie
Copy link
Collaborator

The resolution of the group at the London f2f was to use Javascript

@msporny
Copy link
Member

msporny commented Aug 1, 2016

The resolution of the group at the London f2f was to use Javascript

Link to resolution?

@adrianhopebailie
Copy link
Collaborator

w3c/payment-handler#3

@msporny
Copy link
Member

msporny commented Aug 1, 2016

That link just says "RESOLVED at London f2f", which is an inadequate resolution to an issue. If you follow the discussion thread only Ian and yourself are involved in all of the threads combined (that I could see).

To be clear, I'm willing to try this approach but feel uncomfortable about it until we have more than just one of the browser vendors weighing in on the proposal. What do @adrianba, @zkoch, @rsolomakhin, and @tommythorsen think about the proposal?

I'm also calling resolutions like this out because if we say there was a WG resolution, we should be able to point to where that resolution happened as well as who participated in that resolution (as a W3C member, I expect to be able to see this sort of information). This also really matters when it comes to CR. If we say the WG resolved to do X or Y, we need to demonstrate support and opposition for the resolution. If we don't do that, it makes it very easy to do this during CR: "I object to the resolution because there is no documentation to backup the resolution."

@msporny
Copy link
Member

msporny commented Aug 1, 2016

@dlongley Didn't you say there was some issue w/ postMessage and passing around PaymentRequest objects in the polyfill you did a few years ago?

@dlongley
Copy link
Contributor

dlongley commented Aug 1, 2016

The problem had to do with missing messages before the listener for messages is set up. I assume that a browser could fix that problem somehow.

@webpayments
Copy link

On 8/1/16 4:45 PM, Dave Longley wrote:

The problem had to do with missing messages before the listener for
messages is set up. I assume that a browser could fix that problem
somehow.

Definitely -- basically, the context for the payment app would be
instantiated and given one event cycle to register any callbacks it
needed to before any payment messages were sent its way. This is similar
to how WebRTC handles Identity Providers (cf.
http://w3c.github.io/webrtc-pc/#sec.identity-proxy)

Adam Roach
Principal Platform Engineer
abr@mozilla.com
+1 650 903 0800 x863

@adrianhopebailie
Copy link
Collaborator

@msporny I'm not sure what more you want in the text of the resolution. There was a payment apps breakout at the f2f and during that session the group resolved to use Javascript.

There were no minutes of the breakout so unfortunately there is no record of the conversation other than the report back in the main meeting afterwards.

@zkoch and @adrianba were not in the breakout sessions as they were involved in a separate discussion and @rsolomakhin was in the other breakout session on PMIs. @tommythorsen was not in London but Lars was in the breakout representing Opera.

At this stage we need to still get the spec updated to reflect this decision at which point those that weren't in the breakout are welcome to provide their input.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants