feat: Add Payment Authentication Actions#458
Conversation
aneeshali
left a comment
There was a problem hiding this comment.
Thanks a lot @raginpirate for this PR. Added a few comments based on the last discussion.
fa54c5c to
021b31b
Compare
aneeshali
left a comment
There was a problem hiding this comment.
Thanks a lot @raginpirate for a productive discussion. Left a couple minor comments.
| challenge, decline the payment, or escalate according to the owning handler's | ||
| rules. | ||
|
|
||
| If the action times out or the surface fails to load, the platform follows the |
There was a problem hiding this comment.
Have a question/comment on semantics of the DDC step. Based on EMVCo, device fingerprint (DDC) is optional and I cannot identify a clear instruction of the follow step in case of DDC failure (timeout after 10s for example) or even the fact that ACS nay not even provide a method URL. I would normally expect in case of failure of DDC step to proceed with authentication request (AReq) and notify that in the completion indicator threeDSCompInd . Is this intentional or am I missing something ?
There was a problem hiding this comment.
Hey @dumitru-adyen 👋
I think the key framing here is that this approach is intentionally trying to avoid re-implementing the EMVCo spec inside UCP. A few important points:
- UCP does not specify how a business/PSP deals with receiving a DDC / 3DS Method URL from its provider.
- The platform does not need to see or learn about DDC if it is skipped by either the provider or the business, including cases where the ACS does not provide a method URL.
- The platform also does not need to learn the domain outcome of the DDC step. It only needs to know that the platform-facing action surface has completed so it can re-drive the checkout operation.
You bring up a good point about timeouts though. I don’t want platforms to be responsible for the EMVCo-specific meaning of a DDC timeout or for setting/deriving provider state like threeDSCompInd. But we should define a UCP frame abandonment policy: if the invisible surface does not complete within the configured timeout, the platform can abandon/unmount the frame and re-drive the checkout operation, giving the business/PSP a chance to re-emit DDC, proceed without it, emit a challenge, or abandon/escalate based on its own provider state.
| ] | ||
| }, | ||
| { | ||
| "name": "pa.error", |
There was a problem hiding this comment.
For payment service providers a bit more granularity here can be important to make a difference between a failure and a shopper drop off (shopper left the session without completion). From authentication perspective this metrics offer different insights and makes troubleshooting and correlations easier to spot.
There was a problem hiding this comment.
From my POV I expected that metric to be conveyed on the backend source of truth between the business and the provider; I am not certain it makes sense for that context to be shared with the platform; an opaque "done" seems sufficient on their end, but I'm open to understanding if that data point (beyond error) is important to them.
| The action code is: | ||
|
|
||
| ```text | ||
| dev.ucp.payment.device_data_collection |
There was a problem hiding this comment.
Discussed a bit already, but in our case the ddc and challenge are wrapped under the same redirect url. My understanding is that as long as the postMessage data ("method": "pa.done") is used this clearly defines the completion as such. Would need a different payment-action defined.
There was a problem hiding this comment.
👍 Yeah exactly! You can use the exact same endpoint for either action, as long as it adheres to the spec. And the business is the one who with the additional BE data of the payment request they start, can properly surface that URL with the right contextual action code.
| ```json | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "method": "pa.done", |
There was a problem hiding this comment.
rather than having a separate postMessage design for UCP and our own direct integration or clientside SDK use we would likely add key:values in the postMessage for our own purposes. I would hope/assume these would be ignored by UCP?
these could be additional identifiers for support purposes or expanding on the detail of the outcome e.g. authenticated, rejected, unavailable....
There was a problem hiding this comment.
Yup totally; additional properties is the supported default for any object passed over UCP. This can empower you to adhere to the subset standard while growing the superset and I'd advocate you can always push for more of that superset when it makes sense for that information to live with the platform and not just the business!
There was a problem hiding this comment.
@raginpirate sorry if this is a bit late but a few additional thoughts came up now I'm getting in to the details of feature creation:
- should
methodactually beresultas this is the one direction postMessage? - if you make
result(ormethodif I'm wrong) an object the design becomes more open in terms of allowing others to use the standard jsonrpc result design e.g.
{
"jsonrpc": "2.0",
"result": {
"event": "pa.done", // used by UCP
"outcome": "3dsAuthenticated", // could be any key:value for use by the gateway e.g. used by clientside SDK
},
"id": 1
}This is all within the context of wanting to have a single postMessage design for both direct 3ds integration (with the gateway) and extending it for UCP usage
Also means that for other postMessages we plan to omit such as when a challenge is required we can just remove the event from the result object as UCP does not need to react to this
we would probably add pa.challenged or pa.prompt instead so can be parsed reliably for the challenge case
There was a problem hiding this comment.
Thanks @kmfreeman — using one postMessage design for both direct gateway integrations and UCP is definitely the goal!
I believe method is the correct JSON-RPC shape here. This is because we're expecting the frame to postMessage that event to the parent page, and result is undefined because there is no expected response to carry back to the parent page after receiving it.
Additional params such as outcome or provider correlation data can still support a direct gateway SDK. UCP Platforms only process the fields defined by the active Action contract and ignore other params.
021b31b to
8f3d43b
Compare
aneeshali
left a comment
There was a problem hiding this comment.
Thanks Daniel for driving this alignment across may parties.
| "messages": [ | ||
| { | ||
| "type": "error", | ||
| "code": "action_failed", |
There was a problem hiding this comment.
I was wondering if we want to highlight some of the possible values for code along with action_failed, and document them as guidance.
| "name": "pa.done", | ||
| "summary": "Payment action surface completed", | ||
| "description": "The loaded payment action surface notifies the platform that the scoped interaction is done from the platform-facing surface's perspective. This does not assert payment success or authentication success; the business determines the outcome when the platform resubmits the UCP operation.", | ||
| "params": [ |
There was a problem hiding this comment.
Should we also set "additionalProperties": true to indicate this can include arbitrary payloads as well?
8f3d43b to
33116ac
Compare
aneeshali
left a comment
There was a problem hiding this comment.
Really appreciate the work on this and the related discussions, @raginpirate. Left a couple of comments to fully understand the implementation specifics.
| and retrieve Checkout. It does not mean authentication or payment succeeded. | ||
| After | ||
| closing the surface, the Platform uses Get Checkout and does not call Complete | ||
| Checkout again to resume the accepted operation. |
There was a problem hiding this comment.
With the approach to complete the flow by calling Get Checkout rather than Complete Checkout, please confirm if the expectation is that the Platform can only perform 2 things:
- Resume the flow if further actions are needed, like proceed with challenge once DDC is complete.
- Mark the flow as completed if the Get Checkout returns a response similar to a successful non-3DS complete checkout call.
I'm wondering how will some of the failure cases be handled gracefully in this scenario. For example, if 3DS fails for whatever reason, the platform will make a subsequent Get checkout call, and the merchant may repeatedly return the same action payload as before. If the platform wants to let the user choose a different payment method or similar remedies, there may not be a way to do it in this scenario. Please share your thoughts on how such cases can be handled.
| - If the surface remains invisible and never requests Buyer interaction, the | ||
| Business emits device data collection. | ||
| - If the surface may display a Buyer challenge, the Business emits 3DS challenge. |
There was a problem hiding this comment.
Some PSPs are adopting a slightly different approach for their merchants in the standard 3DS flows. They provide a single URL, which performs device data collection in a visible manner with some standardized loading screen. Depending on the result of DDC, they may either redirect the user to a challenge UI or just complete the flow and pass the control back to the merchant. We could either consider this as a subcase of three_ds_challenge or we could call out as a separate option. I think what the loading screen will look like is out of scope of this PR but providing clarity on that scenario will be helpful considering this is a relevant pattern.
Description
Introduces
dev.ucp.shopping.payment_authentication, a Checkout extension defining standard browser-surface Actions for payment authentication:dev.ucp.payment.device_data_collectiondev.ucp.payment.three_ds_challengeThis PR is stacked on #582, which defines the common extension-owned Actions primitive. Payment Authentication contributes the concrete Action types, config, rendering behavior, security requirements, notification protocol, deadlines, and Checkout integration needed for DDC and 3DS challenges.
The approach
EMVCo defines the interaction between the issuer’s ACS and the merchant’s 3DS provider, mediated by the cardholder’s device and card-network Directory Server. Businesses and platforms do not have to be involved directly in this specification; often Payment Providers create an abstraction layer around the concerns of the EMVco spec. With this world view in mind, UCP attempts to standardize the abstraction layer that businesses and payment providers truly need to offer when handling 3DS and DDC on arbitrary business OR platform surfaces; a simple signal pattern to resolve or reject the action.
Category (Required)
Please select one or more categories that apply to this change.
ucp-schematool (resolver, linter, validator). (Requires Maintainer approval)Related Issues
#517
#582
Checklist
!for breaking changes).