w3c / payment-request

Payment Request API
https://www.w3.org/TR/payment-request-1.1/
Other
482 stars 183 forks source link

Allow user activation to be delegated to a child frame to trigger request.show() #917

Open danyao opened 4 years ago

danyao commented 4 years ago

Proxying a request from Stripe: A lot of PSPs allow merchants to fully control the look-and-feel of the checkout flow, including the "pay" button. The PSP code is embedded inside an iframe and interacts with PaymentRequest. Since the current Payment Request API spec requires a user activation to trigger request.show(), the aforementioned flow is impossible to implement in a spec-compliant browser because user activation cannot be delegated to child frames.

I think we should consider a modification of the User Activation Delegation through postMessages proposal (https://github.com/w3ctag/design-reviews/issues/347) to allow the user activation token to be passed into an iframe for the purpose of triggering request.show(). By narrowing the scope of the original proposal to just the payments feature, I think we can side step the security and UX concerns in the original proposal.

@marcoscaceres WDYT?

@mustaqahmed FYI

danyao commented 4 years ago

@hofman-stripe FYI

marcoscaceres commented 4 years ago

I need to read https://github.com/whatwg/html/pull/4369, but I'm hopeful we we don't need to special-case .show():

-> if click (activation) => iframe (feature policy or allowpaymentrequest=true) => postMessage({data}) => then a .show() should work, because the parent frame allowed it explicitly.

mustaqahmed commented 3 years ago

I think we would need to pass on a time-limited "webpayment token" after a user click anyways, through a postMessage() or whatever means.

This is because an iframe attribute (similarly a permissions/feature policy) is static in nature, and independent from the timing of a user interaction. Without a time limited token, an iframe attribute could allow the iframe to .show() in only two possible ways: either without a user activation at all (aka, always), or with a user click in the iframe. And none of them are okay for this problem. Hopefully I didn't miss anything.

marcoscaceres commented 3 years ago

I think we would need to pass on a time-limited "webpayment token" after a user click anyways,

Interesting. Is there some concrete JS proposal of what that looks like?

mustaqahmed commented 3 years ago

We have started looking into this, hoping to have a proposal soon.

mustaqahmed commented 3 years ago

We just made a WICG proposal for Capability Delegation which we believe would cover payment request as a special case. Please let us know our thoughts.

mustaqahmed commented 3 years ago

An initial implementation of the API is now available in latest Chrome Canary for testing. To try this, run Chrome 90.0.4414.0 or newer with the command-line flag --enable-blink-features=CapabilityDelegationPaymentRequest, then open this demo.

danyao commented 3 years ago

This is exciting! ^^^ @hofman-stripe FYI

mustaqahmed commented 3 years ago

Capability delegation spec now has a monkey-patch to this (Payment Request) spec to support delegation, see here. Please file issues in that repository with any suggestions/questions, we need to make the spec as complete as possible before we kick off a TAG review.

FYI: @stephenmcgruer

marcoscaceres commented 3 years ago

@mustaqahmed, the patch looks good. Thanks for doing that. Please keep us up to date on DELEGATED_CAPABILITY_TIMESTAMPS landing in HTML.

mustaqahmed commented 3 years ago

I will! Thanks for the quick review. Our plan now is to update the draft with more specific HTML changes and then send out for TAG review.

stephenmcgruer commented 2 years ago

Noting here (where PaymentRequest folks are likely to be listening) that @mustaqahmed has raised a question about the expected lifespan of a delegated payment capability in https://github.com/WICG/capability-delegation/issues/8

I suggested the current transient activation duration seemed correct, to align with the user expectation of 'I clicked and then a thing happened', but input from others is also welcome. One consideration might be if payments expects more time to pass between click and PR.show(), for any reason. (I can't think of any offhand).

rsolomakhin commented 2 years ago

One consideration might be if payments expects more time to pass between click and PR.show(), for any reason

Sometimes there can be a requirement to perform a server round trip to retrieve the most up to date price, for example. PaymentRequest.show() handles that requirement by allowing a promise for updated payment details to be passed into show() as an optional parameter. Therefore, there is no need to account for such a delay in capability delegation API.