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

The relationship between payment apps and service workers #33

Closed
tommythorsen opened this issue Aug 26, 2016 · 50 comments
Closed

The relationship between payment apps and service workers #33

tommythorsen opened this issue Aug 26, 2016 · 50 comments

Comments

@tommythorsen
Copy link
Member

A question came up during our last payment apps task force meeting, regarding what the relationship would be between the payment apps in @adamroach's new payment app proposal, and service workers. The new payment apps in this proposal do have a lot in common with service workers;

  • They are installed into the browser with a lifespan that exceeds that of the web page that installed them.
  • They have the ability to react to certain events (service workers react to fetch requests, payment apps react to payment requests) and pass back a response.
  • Many of the execution lifetime challenges and security challenges are the same.

The new proposal currently describes payment apps as specializations of the dedicated worker, that just happen to be similar to service workers, but there may be benefits to bringing them closer together. The way I see it, we have at least three options:

1. Payment apps are service workers
Going in this direction would mean that we add more functionality to the ServiceWorkerGlobalScope. This added functionality would probably consist of a new Event Handler (onpaymentrequest) and a function call for registering payment methods or payment options with the user agent. Payment apps are registered exactly the same way as service workers (since they are the same), with navigator.serviceWorker.register().

The advantage of this approach, is that it is very simple, both to specify and to implement, and it lets us make use of all the security mechanisms around service workers, The disadvantage is that we would be "polluting" the ServiceWorkerGlobalScope class with functionality that isn't strictly service worker related. There may also be functionality in service workers that we don't want for payment apps, although I'm not sure what that might be.

2. Payment apps inherit from service workers
Inheriting from ServiceWorkerGlobalScope rather than modifying it, should let us make use of most of the advantages of the above approach, while keeping our payment request related API separate from the service worker API. We would have to make our own registration method (PaymentApp.register() or navigator.paymentApp.register()), but this might be considered an advantage, since it would make it clearer what exactly is being registered, and it would let us take additional arguments to the register call.

3. Payment apps look like service workers
This is the scenario I think the new proposal currently describes. Doing it this way, means that we need to duplicate a lot of the specification (and implementation) from service workers. This way is more work, but gives us the freedom to pick and choose what we borrow from service workers and what we don't.

What do you guys think? You are probably aware of more advantages and disadvantages to some of these options, and it would be interesting to have a discussion on this.

@adrianhopebailie
Copy link
Contributor

Thanks for this summary @tommythorsen, this is very helpful.

I am not an expert on how browsers operate internally but the architect in me says option 2 is the best way forward at list until we decide we have to go to option 3.

I see an advantage in option 1 in that it's simple and means re-using existing primitives which is good. Perhaps we could still follow option 1 but instead of having a payment request event just listen for messages and look at the message to see if it's a payment request?

I'd like us to consider carefully the possibility of re-looking at using manifests for payment apps where perhaps the app has no start_url but rather just a service worker (See w3c/manifest#161 for discussion of this lately, I think we have a compelling use case).

Browsers that see the manifest rel link will fetch the manifest, see it is for a payment app and prompt the user to register it. If the user accepts then they will register the payment app (service worker).

Worth getting feedback here from @marcoscaceres and @jakearchibald, I suggest we try to meet at TPAC as they will need a lot of context.

@dlongley
Copy link
Contributor

dlongley commented Aug 26, 2016

It sounds to me like option 2 is the best option until option 3 clearly becomes a necessity. Polluting the ServiceWorkerGlobalScope with payment-specific stuff will not only be ugly, but it will set a bad precedent. Furthermore, there is, in my view, a great advantage to developers in "saying what you mean" with appropriately named payment app registration methods and messages and so forth.

Perhaps we could still follow option 1 but instead of having a payment request event just listen for messages and look at the message to see if it's a payment request?

Having to interpret something based on the context because it happens to "look like" what you want requires that you take on considerably more (unnecessary) knowledge about the underlying architecture and details of the system that has been extended. Let's keep this as simple as we can
for developers and not introduce any mysteries that they may feel they need to go off and solve to really understand the API.

Edit: That may be overstating it for this particular case (message type checking), but wanted to put those thoughts out there.

@jakearchibald
Copy link

jakearchibald commented Aug 26, 2016

It sounds to me like option 2 is the best option until option 3 clearly becomes a necessity. Polluting the ServiceWorkerGlobalScope with payment-specific stuff will not only be ugly

I'm not too worried about this. In fact, it seems worse that users would have to manage the lifecycle of yet another thing.

If it's a JS context that wakes up to handle an event, potentially without a page on the origin being open, that's a service worker. This is why things like push, sync, and potentially alarms & geofencing live there. The precedent is already there, and by design.

Joining these means developers could use push messages to update a payment app's details etc.

@dlongley
Copy link
Contributor

dlongley commented Aug 27, 2016

I'm not too worried about this. In fact, it seems worse that users would have to manage the lifecycle of yet another thing.

I don't entirely follow this concern. By "users" did you mean the end users or the users of the API?

End users are already going to be managing, installing, removing, and interacting with Payment Apps in a number of ways that may be different from typical service workers -- if for no other reason than in how they are surfaced. In any event, end users likely won't have any understanding of the implementation or architecture details here (nor will they care).

If you meant users of the API, what is the extra overhead that they would incur with option 1 vs. option 2? Perhaps this isn't true for all Payment App implementers, but I would expect most to see Payment Apps as their own (sub)class of thing, even if their behavior inherits greatly from service workers. But this is why an inheritance model seems to make sense. It doesn't make sense to me that any service worker may show up in the list of Payment Apps that I could use to complete a payment request. However, that doesn't mean that we necessarily need to establish a new class of thing in order to make that distinction manifest. This is just an explanation for why inheritance seems to make sense to some of us here.

If it's a JS context that wakes up to handle an event, potentially without a page on the origin being open, that's a service worker. This is why things like push, sync, and potentially alarms & geofencing live there. The precedent is already there, and by design.

I think only option 3 would cause a Payment App not to be a service worker; for options 1 and 2, it's just a question of how the necessary extensions are achieved. Of course, you link to the extensibility section on service workers which is definitely the primary source of guidance we should attempt to follow here. We should assume that a lot of thought has been put into this previously and try to use the framework put forward. So thank you for the pointer.

@dlongley
Copy link
Contributor

As linked from the service worker extensibility section, the Notifications API is an example of a spec that extends the service worker spec:

https://notifications.spec.whatwg.org/#service-worker-api

@dlongley
Copy link
Contributor

@jakearchibald also mentioned some other APIs that extend service workers:

Push API
BackgroundSync
Web Alarms
Geofencing

@jakearchibald
Copy link

This is exactly what it was designed for. There'd need to be a really good reason to create a new worker type for this, and I'd rather look at ways we can change service worker if it doesn't quite fit.

@sideshowbarker
Copy link
Collaborator

About option 3 vs actually using service workers:

3. Payment apps look like service workers
This is the scenario I think the new proposal currently describes. Doing it this way, means that we need to duplicate a lot of the specification (and implementation) from service workers.

Clearly in general that’s an anti-pattern we should be trying very hard to avoid for any new features we add to the platform. To me, if we advocate for a mechanism that we know will duplicate a lot of the functionality already provided by service worker, then the burden of proof should be on us (in the Payments WG) to clearly explain to the rest of the people working on features for the platform why we need to create a new parallel thing rather than re-using the work they have already done.

[about basing the payment-apps API on service workers]

There may also be functionality in service workers that we don't want for payment apps, although I'm not sure what that might be.

Me neither. Again I think the burden on proof should be on us in the Payments WG: If we think there is some functionality from standard service workers that we would not want exposed in the payment-apps case, then we have an obligation to clearly identify what that is.

[about not basing the payment-apps API on service workers]

This way is more work, but gives us the freedom to pick and choose what we borrow from service workers and what we don't.

It seems to not be clear at all that we need that freedom or that we ever will. So it is not clear that there are any real-world benefits in practice compared to the cost of making users “have to manage the lifecycle of yet another thing” (as @jakearchibald put it).

Another clear benefit of basing the payment-apps API on service worker is, if/when deficiencies in SW get identified that require fixes and refinements—which is a very normal thing that happens with core features of the platform—then for the payment-apps API, we automatically get the benefits of those fixes and refinements for free, without needing to port them over to our parallel thing.

@dlongley
Copy link
Contributor

dlongley commented Aug 27, 2016

Using this model, I think we would end up with code something like this:

// https://example.com/serviceworker.js (the Payment App)
this.onpaymentrequest = function(event) {
  // handle the payment request event and return a payment response
};

// https://example.com/webapp.js (the website that registers the Payment App)
navigator.serviceWorker.register('serviceworker.js').then(
  function(serviceWorkerRegistration) {
    // pass a 'manifest' into the payment app manager interface to indicate
    // which payment methods are supported so the payment app can show up
    // in the payment mediator when appropriate
    serviceWorkerRegistration.paymentAppManager.register(manifest).then(
      function(registrationResult) {
        // do whatever with the registration result
      }, function(error) {
        console.log(error);
      }
    );
  });

Obviously, the name paymentAppManager can be bike shedded. Maybe we even want it to be paymentMediator.

@sideshowbarker
Copy link
Collaborator

[About 1. Payment apps are service workers vs 2. Payment apps inherit from service workers]

I think we could just go with “payment apps are service workers“. I see no need to go with the kind of “Payment apps inherit from service workers” alternative described.

I think that conclusion can be reached pretty clearly from a reading of the Service Workers spec (especially the parts of the SW spec @jakearchibald cites) and from reading other specs for technologies that build on SW (cited by @dlongley).

Payment apps are registered exactly the same way as service workers (since they are the same), with navigator.serviceWorker.register().

Yeah, I think there’s no reason to do otherwise, and @dlongley’s snippet shows what it’d look like.

[about “payment apps are service workers”]

The disadvantage is that we would be "polluting" the ServiceWorkerGlobalScope class with functionality that isn't strictly service worker related.

I think reading of the section of the SW spec @jakearchibald cites and a reading of the specs for the existing built-on-SW specs that @dlongley cites makes it clear that adding a new EventHandler to ServiceWorkerGlobalScope and a new method to ServiceWorkerRegistration would not be seen as bad/polluting but instead is actually exactly how SW was designed to be built on.

@domenic
Copy link

domenic commented Aug 27, 2016

I agree with the others that state that option 1 makes the most sense. The OP expresses concerns about polluting service workers with "unrelated" functionality, but this is very much related to the core service worker mission, of having a ... service ... worker that runs in the background and reacts to events in order to provide a service (whether that be fetch interception, geofencing, push notification reactions, or payment request processing).

@adrianhopebailie
Copy link
Contributor

It sounds like there is rough consensus for option 1 which I think is great, it feels like a good extensible web story.

The specifics of how we do option 1 is probably still tdb.

@adamroach - as the author of the existing payment app proposal your opinion would be highly valued here.

I would still like to understand how we could loosely couple the implementation from the registration such that we can handle different registration methods (declarative via a manifest vs through an API call).

I hear @jakearchibald say "this is what ServiceWorkers were designed for" which is great, but I'd like to hear also from @marcoscaceres about using manifest.

My early proposals for the payment apps API intended to use the extension points of the manifest spec to provide "supported payment method" meta-data and I wonder if that isn't still a good idea.

i.e. Could a variation of @dlongley 's suggested code be used to register any ServiceWorker using a manifest instead of just the sw.js. This allows meta-data about the SW to be in the manifest and not need to be called via new serviceWorkerRegistration extensions.

I am also not convinced that we need a new onpaymentrequest event. Why is inspecting a message and deciding if it's a payment request a bad thing? Any onmessage logic will need to inspect the message to decide what to do next anyway.

This also opens up an interesting use case where a site that has it's own payment app installed could pass a payment request directly to that app and bypass the mediator-based app selection completely. This feels like a good thing but need to think about it a bit more.

Something like:

// https://example.com/serviceworker.js (the Payment App)
this.onmessage = function(event) {
  // If message is payment request then process it and return a payment response
};

// https://example.com/webapp.js (the website that registers the Payment App)
var manifest = 
{
    "name": "Example Payment App",
    "start_url": "https://boo", //Not sure what would go here?
    "service_worker": "serviceworker.js",
    "payment_methods" : ["basic_card", "http://example.com/pay"]
};

navigator.serviceWorker.register(manifest).then(
...
);

@jakearchibald
Copy link

What's the benefit of having this in the manifest? Is there an issue I can read to catch up?

@tommythorsen
Copy link
Member Author

I have to admit, I was originally in favor of option 2, but now that I see all of your comments, it seems that option 1 is the right way. It would be really great if we could follow the examples of the push, sync and notifications APIs for integrating with service workers.

@adrianhopebailie:

I am also not convinced that we need a new onpaymentrequest event. Why is inspecting a message and deciding if it's a payment request a bad thing? Any onmessage logic will need to inspect the message to decide what to do next anyway.

Passing the payment requests as messages to onmessage would probably work just fine. There seems to be some precedent for adding explicit event handlers, though; The Push API adds onpush and onpushsubscriptionchange, the Notifications API adds onnotificationclick and onnotificationclose, and the Sync API adds onsync.

On the other hand, if the payment requests were HTTP requests, we could use onfetch...

@adrianhopebailie
Copy link
Contributor

adrianhopebailie commented Aug 29, 2016

What's the benefit of having this in the manifest?

A Payment App has some meta-data (the list of payment methods is can handle) that is important to register with the browser during registration. A manifest seems like the right way to do this.

That is not so say it's the only way but it seems like there could be better alignment of what's being done to extend ServiceWorkerRegistration and extend manifest.

@tommythorsen - I don't have a strong personal preference between onmessage and a new event but would like to know what the guidance from the designers of ServiceWorker is in this case so we're being consistent.

For example I note that for Notifications two new methods are defined directly on the ServiceWorkerRegistration interface but for the other APIs there is a new interface (example: ServiceWorkerRegistration.pushManager).

If this is really is the intended use for ServiceWorker some extensibility guidance would be helpful here.

@jakearchibald
Copy link

Landing stuff in onmessage that wasn't sent via the user's call to postMessage feels weird.

I think the fetch idea may be worth exploring though. If a payment app can be described purely in terms of HTTP requests, then service worker doesn't need to be an explicit dependency, but it becomes beneficial through existing mechanisms.

@zkoch - we threw this idea around a few months ago, any existing discussion elsewhere?

@adrianhopebailie
Copy link
Contributor

If a payment app can be described purely in terms of HTTP requests, then service worker doesn't need to be an explicit dependency, but it becomes beneficial through existing mechanisms.

@jakearchibald that was the original proposal I made a few months back which is probably why @tommythorsen is bringing it up. My argument in favor of an HTTP request is that it is less platform specific and so could be handled by non-browsers as easily as a ServiceWorker using onfetch.

We discussed this at our face to face in June and the consensus was to use ServiceWorkers.

The thinking went something like this:

  • There are two cases
    1. Sending the payment request to a remote service
    2. Processing it locally
  • If the browser forwards payment requests as an HTTP POST then it's easy to intercept in a ServiceWorker and process locally, likewise if it's sent to a ServiceWorker then it's easy to create a new request and send it to a remote service so both WORK the question is which feels easier to use.
  • I think the consensus was that for Web developers writing Javascript code and not needing to catch a raw request and inspect it to decide if it's a payment request felt more natural.

Lots of previous discussion:

The current ED still uses HTTP:

@adrianhopebailie
Copy link
Contributor

@jakearchibald, to address your other comment:

Landing stuff in onmessage that wasn't sent via the user's call to postMessage feels weird.

That's true and is probably a good reason to not use an HTTP request and onfetch too.

The more I think about it it feels like if we're designing a new API in navigator scope then it makes sense for this to have a corresponding new API in ServiceWorker (and possibly ServiceWorkerRegistration) scope too.

I.e. If we aren't forcing websites to submit a payment request using fetch or postMessage then we shouldn't force a payment app to process them through onfetch or onmessage.

So, I'm coming around to @dlongley 's proposal. Still keen to hear what @adamroach thinks though.

@jakearchibald
Copy link

I think the consensus was that for Web developers writing Javascript code and not needing to catch a raw request and inspect it to decide if it's a payment request felt more natural

If that's the reason, then onmessage isn't the answer, as the developer's still having to catch something raw. A specific payment event means you can have your own event object, with methods like paymentEvent.plsShowThisUI(url).

I haven't looked at it enough to know if fetch or a custom event is better, but onmessage feels like a poor compromise.

@adamroach
Copy link
Contributor

@adrianhopebailie -- still digging through some of the background material here, but I think the general approach here is pretty sound. In particular, I far prefer the use of a new event rather than message queues (in fact, I argued for a similar design in London).

I'll note that going with actual service workers settles the issue of updating payment apps (we leverage the normal SW update mechanism), and makes it so we don't have to re-invent a registration concept for payment apps (in fact, that's one of the things I like most about this approach).

As we discussed on the call today, I plan to revise the jsapi proposal to reflect this approach in time for our call next week. I think I have enough information in this issue to do so.

@jakearchibald
Copy link

Happy to take part in these calls if anyone thinks it'd be useful

@sideshowbarker
Copy link
Collaborator

@jakearchibald For a link to the call info along with other stuff, see https://github.com/w3c/webpayments/wiki/PaymentApp_Notes

There’s an .ics file with the event data but here are the actual details:

Time: Wednesdays from 9am to 10am US/East

https://mit.webex.com/mit/j.php?MTID=mab3c7a1fb772cbcbf39b054b2ebd9183

+1-617-324-0000 US Toll Number
Access code: 640 633 363

@rsolomakhin
Copy link
Collaborator

Great to see broad consensus on using ServiceWorkers. A question remains: what should we do with manifests, if anything? Let me try to convince you that we need manifests.

Here's why I think manifests are useful. Suppose a merchant website at https://shop.com calls PaymentRequest with a supported payment method of https://bobpay.xyz. The user has installed a Service Worker from https://alicepay.xyz that supports https://bobpay.xyz as a payment method. Should the browser allow AlicePay to respond to BobPay's payment method? One way to authorize AlicePay is to check https://bobpay.xyz/payment-manifest.json to see if there're any restrictions in there. If BobPay's payment-manifest.json specifies no restrictions or explicitly allows AlicePay to use its payment method, then the browser should show AlicePay as one of the payment app options.

Now that (I hope) you're convinced of usefulness of manifest files, what should be inside of them? These manifests specify payment app restrictions, if any. Restrictions can be expressed as a whitelist of allowed payment apps.

How should payment apps be identified? Service Workers can be downloaded from the web. The URLs where they reside can serve as the payment app identifiers. So the service worker at https://bobpay.xyz/sw.js, for example, can be the payment app identified as https://bobpay.xyz. So let's go with URLs to identify payment apps.

Example https://bobpay.xyz/payment-manifest.json file with a whitelist of payment apps:

{
  "externally_supported_apps": ["https://alicepay.xyz", "https://charliepay.xyz"]
}

Example https://bobpay.xyz/payment-manifest.json file without payment app restrictions:

{
  "externally_supported_apps": ["*"]
}

Browsers need to know how to display the payment app Service Workers in UI, so the user can select them. For example, browsers may need the title of a payment app along with its icon in several sizes. The web already has a way to specify this through manifests.

Before we get into specifying payment app Service Worker titles and icons, let's not forget native apps, either. Payment apps can be Service Workers, Android apps, iOS apps, Windows apps, etc. Therefore, it's useful to split up payment-manifest.json into several sections: "web", "android", "ios", "windows", etc.

  • The "web" section can specify:
    • Human-readable title of the app.
    • App icons in several sizes.
    • (Service Worker will register itself, so there's no need to specify the location of the service worker.)
  • The "android" section can specify:
    • A way to identify a payment app (package name and signing certificate fingerprint).
    • Where the app can be downloaded, if it's not installed yet.
    • (There's no need to specify icons and title, because that is already available from the OS.)
  • And so on...

I think you see the pattern. Here's an example of what https://bobpay.xyz/payment-manifest.json might look like. Two points before we read into this too much:

  1. I do not presume that any of this is set in stone and final.
  2. Native apps should live at extension points of the spec. The spec should describe only web apps, IMHO.
{
  // Other payment apps that can use "http://bobpay.xyz" payment method.
  "externally_supported_apps": ["https://alicepay.xyz", "https://charliepay.xyz"],

  // Description of the Service Worker payment app "https://bobpay.xyz".
  "web": {
    "name": "BobPay - The World's Best Way to Pay",
    "short_name": "BobPay",
    "icons": []
  },

  // Descriptions of the Android payment app for "https://bobpay.xyz".
  // Using a list here enables support for developer version and
  // production version of the Android app, for example.
  "android": [{
    "platforms": {
        // Where the app can be downloaded, if it's not installed.
        "play": "https://play.google.com/store/apps/details?id=xyz.bobpay.app1",
        "mios": "https://mi.cn/store/id=xyz.bobpay.app1"
       },
      // Next two fields provide a way to authorize a locally installed app.
      "package": "com.example.app1",
      "sha256_cert_fingerprints": ["14:6D:E9:83:C5:73:06:50"]
  }],

  // Descriptions of the iOS payment app for "https://bobpay.xyz".
  "ios": "TBD"

  // And so on...
}

Thoughts?

@adrianhopebailie
Copy link
Contributor

@rsolomakhin I agree that manifests are very useful but I think you are conflating payment app manifests and payment method manifests.

A payment method manifest (like https://bobpay.xyz/payment-manifest.json) describes the payment method, including the id's of apps that are allowed to handle payment requests for that method. This is a new concept and we need to design these but I don't think they should contain anything about payment apps other than the id's of those that support the payment method (a foreign key relationship).

I think we'd also get some value out of using payment app manifests too and should be leveraging the existing work done on appmanifest. This is where we'd define things like the app icons, label and alternative versions in app stores etc. (This is all already defined for app manifest).

App manifest also has extension points which we can use to define payment app meta data like supported payment methods: https://www.w3.org/TR/appmanifest/#extensibility

@rsolomakhin
Copy link
Collaborator

I think you are conflating payment app manifests and payment method manifests.

That's intentional. We could have separate payment-app.json and payment-method.json, but placing the data in a single file will save a round-trip. Is it a bad idea?

If we prefer to re-use appmanifest, then let's put externally_supported_apps in there at the extension point.

I think we'd also get some value out of using payment app manifests too and should be leveraging the existing work done on appmanifest. This is where we'd define things like the app icons, label and alternative versions in app stores etc. (This is all already defined for app manifest).

One downside of the related_applications list in appmanifest is lack of authentication information for apps. I would like to add sha256_cert_fingerprints for Android apps, but the related_applications algorithm does not have an extension point. Is it possible to add an extension point there in the appmanifest spec?

@ianbjacobs
Copy link
Contributor

@rsolomakhin wrote:

We could have separate payment-app.json and payment-method.json, but placing the data in
a single file will save a round-trip. Is it a bad idea?

Personally, I am open to the idea of "one manifest". I look forward to discussing further at the FTF meeting.

Ian

@adrianhopebailie
Copy link
Contributor

Is it a bad idea?

I think it's a very bad idea. They are different things so trying to combine them is a bad idea. The app manifest will be fetched when the app is registered whereas the payment method manifest might be fetched during a checkout or during app registration.

Note that during app registration fetching and processing manifests is a background process that is not blocking user interactions so the number of round-trips is immaterial.

If we prefer to re-use appmanifest, then let's put externally_supported_apps in there at the extension point.

We can't do that because this is an app manifest (not a payment method manifest).

Is it possible to add an extension point there in the appmanifest spec?

We should raise that with the app manifest editors

@zkoch
Copy link

zkoch commented Sep 7, 2016

I don't think it's a bad idea. I think we can think of it not as a payment-method manifest or a payment-app manifest but as a "heres-how-i-participate-in-the-paymentrequest-ecosystem" manifest.

@rsolomakhin
Copy link
Collaborator

If @adrianhopebailie and others feel strongly in favor of separation of payment app manifest and payment method manifest, then I can be convinced as well :-). After all, the payment method manifest is extremely simple:

{
  "externally_supported_apps": ["https://alicepay.xyz", "https://charliepay.xyz"],
}

@adrianhopebailie
Copy link
Contributor

After all, the payment method manifest is extremely simple

Indeed!

The point here is that for a the payment method http://bobpay.xyz why would the manifest at https://bobpay.xyz/payment-manifest.json contain any data about the app https://alicepay.xyz? That makes no sense.

The manifest describing the app https://alicepay.xyz should be hosted at the origin alicepay.xyz.

I think we're going off topic here though so maybe we need a new thread discussing manifests

@rsolomakhin
Copy link
Collaborator

To bring the discussion back on topic: Yay Service Workers! 👍

@zkoch
Copy link

zkoch commented Sep 7, 2016

The point here is that for a the payment method http://bobpay.xyz why would the manifest at https://bobpay.xyz/payment-manifest.json contain any data about the app https://alicepay.xyz? That makes no sense.

I agree that makes no sense, but I don't think that's whats bring proposed. But I agree we're off topic, so can take this to another issue and/or discuss at TPAC.

To bring the discussion back on topic: Yay Service Workers!

👍

@jakearchibald
Copy link

@rsolomakhin

Suppose a merchant website at https://shop.com calls PaymentRequest with a supported payment method of https://bobpay.xyz. The user has installed a Service Worker from https://alicepay.xyz that supports https://bobpay.xyz

Due to lack of experience I'm a little confused by this example. Can you give me something more real-world where the merchant, payment handler, & payment method are distinct?

The "primary key" of a service worker registration is its scope, which allows for multiple service worker registrations on a single origin. A single service worker registration can update its script URL, but its scope URL is fixed. Seems like the scope should be used to identify a payment app.

There's still no update model for manifests, so the more information you put in there, the more updating trouble you'll land in. You'll either have to live with out-of-date info, or request the manifest every time you need the info from it, and that'll slow things down. If this information was set using APIs in a service worker, its updating is in the control of the origin owner.

Is it useful to specify Android/iOS in that much detail? As far as I know, native apps can already hijack navigations, so can't they just hijack the payment process in a similar way? The spec could provide hooks for this, eg "If bobpay's native app is install, it can do what it wants as long as it returns to the next step".

@dlongley
Copy link
Contributor

dlongley commented Sep 9, 2016

@jakearchibald,

Due to lack of experience I'm a little confused by this example. Can you give me something more real-world where the merchant, payment handler, & payment method are distinct?

We refer to the "payment handler" as a "payment app". Here's a real world example:

You go to expedia.com (the merchant) and book a hotel. When it's time to checkout, Expedia lets you pay with bitcoin (the payment method). Your browser lets you choose your Coinbase wallet (the payment app) to pay. This selection is offered because the Coinbase app indicates that it supports the bitcoin payment method.

This new Web Payments architecture allows new payment methods to be created that could potentially be implemented by a variety of different payment apps. The creators of some payment methods will want to restrict which payment apps can implement their method and we're exploring specifying this via a manifest. Other payment methods will not have this sort of restriction.

@jakearchibald
Copy link

jakearchibald commented Sep 9, 2016

But why does bitcoin need to grant permission for Coinbase to use bitcoin? - ah just read the replies above, seems others have pointed out that doesn't make sense

@jakearchibald
Copy link

Also seems I had this tab open for days and wrote my reply without seeing all the intermediate comments, sorry!

@jakearchibald
Copy link

jakearchibald commented Sep 9, 2016

My thoughts in summary (now I've caught up with the rest of the thread):

You could have:

sw.js

self.registration.payments.register({name: 'Foopay'});

Or:

sw.js

self.registration.payments.register('//manifest.json');

combined with manifest.json

{"name": "Foopay"}

The former can be updated whenever page or service worker code runs (eg push message). The latter is dependent on an as-yet-undefined update model for the manifest.

@dlongley
Copy link
Contributor

dlongley commented Sep 9, 2016

@jakearchibald,

But why does bitcoin need to grant permission for Coinbase to use bitcoin?

They don't. But what's being explored is whether some other payment methods may want to restrict the usage of their "proprietary" payment method to certain applications, e.g. PayPal.

@dlongley
Copy link
Contributor

dlongley commented Sep 9, 2016

@jakearchibald,

The discussion about "policing" payment apps is related but a bit off topic -- it's taking place over here:

w3c/payment-method-id#11

I think here we're just discussing the shape/purpose/specification/use of manifests with respect to payment apps as service workers.

@rsolomakhin
Copy link
Collaborator

The [manifest] is dependent on an as-yet-undefined update model for the manifest.

I was thinking of using Cache-Control for manifest expiration. A programmatic way to update this information is also useful. One possibility is to use Service Workers to manage both payment app's manifest and payment method's manifest. That way push messages can be used to update either piece of information.

@jakearchibald
Copy link

jakearchibald commented Sep 11, 2016

I was thinking of using Cache-Control for manifest expiration.

So if the manifest expires, is it no longer an installed payment app? Or will every matching stale manifest be refetched when a site calls new PaymentRequest()? What if one of those requests hangs?

@rsolomakhin
Copy link
Collaborator

If we use Cache-Control and the manifest expires, the browser would refetch
the manifest without blocking the user. If the manifest fails to download
due to network troubles, e.g., timeout, then browser should not uninstall
the associated apps.

Can Service Workers give more control to the developers as to when their
manifests should be updated?

On Sep 11, 2016 7:13 AM, "Jake Archibald" notifications@github.com wrote:

I was thinking of using Cache-Control for manifest expiration.

So if the manifest expires, is it no longer an installed payment app? Or
will every matching stale manifest be refetched when a site calls new
PaymentMethodData()? What if one of those requests hangs?


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#33 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA-yGdhF5rCowQ2MepbBlaHYCQuaobFMks5qpAyEgaJpZM4Jt-H8
.

@marcoscaceres
Copy link
Member

FWIW, I'm in support of option 1.

@adrianhopebailie

I am also not convinced that we need a new onpaymentrequest event. Why is inspecting a message and deciding if it's a payment request a bad thing? Any onmessage logic will need to inspect the message to decide what to do next anyway

That would be really confusing. "message" events are for "post message". Having a specific payment event is less confusing, and allows the custom payment stuff to be part of the event itself (and avoids polluting the global scope).

I see that similar consensus emerged further down the thread, which is good.

@rsolomakhin

, but placing the data in a single file will save a round-trip.

This doesn't matter in a H/2 world. It's premature optimization.

I'd also like to note that the collaboration across multiple sites to perform a payment feels a bit like "foreign fetch".

I also remain somewhat unconvinced that a web manifest has a big role to play here. I'm still trying to digest the use case, but it doesn't feel right to me at first glance.

@jakearchibald
Copy link

@rsolomakhin

If we use Cache-Control and the manifest expires, the browser would refetch the manifest without blocking the user.

But if shop.com calls:

new PaymentRequest([{
  supportedMethods: ["visa", "bitcoin"]
}, {
  supportedMethods: ['bobpay.com']
}, {
  supportedMethods: ['foopay.com']
}]).show()

…and the user has "installed" bobpay.com and foopay.com as payment apps, but their manaifests are stale, is show() now blocked on fetching those manifests? If one of those requests hangs, is the whole UI hanging?

Can Service Workers give more control to the developers as to when their manifests should be updated?

It's something that could be added in future, but not right now. However, service worker already gives the developer full control over when service worker registrations and other forms of storage are updated.

@adrianhopebailie
Copy link
Contributor

To be clear for @jakearchibald and @marcoscaceres there are two manifests being proposed (although @rsolomakhin would like these combined in cases where the payment method owner only allows their own payment app to be used).

The first is a manifest for the payment method which could describe, among other things, which payment apps can be used to pay using the payment method, which origins these apps can come from (and now possibly which merchants can detect for the presence of an app supporting that method - see w3c/payment-request#247) etc.

The second is akin to app manifest and describes the payment app itself. Our examples are already re-using numerous concepts from app manifest so it seems like a good fit. The issue is that the relationship between manifests and service workers seems poorly defined at the moment so while we'd like to use manifests we may have to provide imperative versions of everything in a manifest through the service worker registration hook instead.

Question to the two of you is, can we come to an agreement about using app manifest with service workers in a way that makes sense for apps where the service worker really is the app or is app manifest just a way to put icons and context on html apps?

@jakearchibald
Copy link

@adrianhopebailie

The issue is that the relationship between manifests and service workers seems poorly defined

It isn't defined because they're pretty separate. Manifests are taking care of all the things that were previously <meta> and <link> clogging up the head of the page. It seems like they're being misused here for payments.

Question to the two of you is, can we come to an agreement about using app manifest with service workers in a way that makes sense for apps where the service worker really is the app or is app manifest just a way to put icons and context on html apps?

I think it's already the latter. If we're already using service worker, what's the justification for adding manifests on top of that?

@marcoscaceres
Copy link
Member

To be clear for @jakearchibald and @marcoscaceres there are two manifests being proposed (although @rsolomakhin would like these combined in cases where the payment method owner only allows their own payment app to be used).

If you can avoid having an external JSON resource, please do so. In w3c/payment-request#247, it seems you are already avoiding using JSON - you have just a regular JS object (...and yes, you should not be able to detect the payment method:))

so while we'd like to use manifests we may have to provide imperative versions of everything in a manifest through the service worker registration hook instead.

We have a similar issue filed here to do that:
w3c/manifest#472

Web Manifest predates the extensible web and service workers, which is why we didn't have an API in the first place. If we were to do web manifest today, we would not do it as JSON - but as an API in Service Workers (hence w3c/manifest#472).

Question to the two of you is, can we come to an agreement about using app manifest with service workers in a way that makes sense for apps where the service worker really is the app or is app manifest just a way to put icons and context on html apps?

What @jakearchibald said and asked.

@dlongley
Copy link
Contributor

dlongley commented Sep 14, 2016

@marcoscaceres,

If you can avoid having an external JSON resource, please do so.

One reason for expressing the manifest as JSON is for reuse in other environments. It follows the Rule of Least Power design principle.

This manifest will likely specify a title, icon/image, and other basic information about a Payment App. A Payment App may be registered with the browser and may use JavaScript (via a service worker), but it could also potentially provide HTTP endpoints for use with the Web Payments HTTP API. Other APIs could also be specified in the future to access the same Payment App. The manifest could be reused here to provide that same information to a payment mediator or to other applications that wish to render some kind of interface for working with it outside of the browser.

By expressing this information as JSON in an external resource -- it means that the Payment App implementer only needs to do so in one place.

Now, an argument could be made that Payment Apps that provide multiple APIs could, for example, in their service worker do a fetch to obtain their manifest, parse it, and then provide it as JavaScript to the paymentAppManager interface. And perhaps that's the model we'll end up with. But I wanted to explain one rationale for having an external manifest and for expressing it in the least powerful programming language. There's a greater potential for Payment Apps than just their use within the browser. Choosing a design that allows us to reuse various aspects of them may result in less burden for the developer and more serendipitous innovation in the future.

@jakearchibald
Copy link

Now, an argument could be made that Payment Apps that provide multiple APIs could, for example, in their service worker do a fetch to obtain their manifest, parse it, and then provide it as JavaScript to the paymentAppManager interface

This sounds like the most extensible thing to do. This means the developer could have the data directly in the service worker, or an external JSON resource, or YAML, or whatever they want.

@ianbjacobs
Copy link
Contributor

With the imminent adoption of text by AdamR I believe we are addressing this issue and therefore I propose to close it. We can move the discussion to review of the text and raise smaller issues in doing so.

Thanks to all!

Ian

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

No branches or pull requests