From 412dc9d43bb1609b9840e4876727271b0bee3e5d Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Mon, 10 Mar 2025 10:08:02 -0400 Subject: [PATCH 1/7] [Spec] Add output enum for isSecurePaymentConfirmationAvailable Fixes https://github.com/w3c/secure-payment-confirmation/issues/284 --- spec.bs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/spec.bs b/spec.bs index 9b0c04d..7512c61 100644 --- a/spec.bs +++ b/spec.bs @@ -73,6 +73,7 @@ spec: web-authn; urlPrefix: https://w3c.github.io/webauthn/ text: authentication extension; url: authentication-extension text: extension identifier; url: extension-identifier text: user member; url: dom-publickeycredentialcreationoptions-user + text: user-verifying platform authenticator; url: user-verifying-platform-authenticator spec: webdriver; urlPrefix: https://w3c.github.io/webdriver/ type: dfn @@ -365,7 +366,7 @@ presumes access to await/async, for easier to read promise handling. const spcAvailable = PaymentRequest && PaymentRequest.isSecurePaymentConfirmationAvailable && - await PaymentRequest.isSecurePaymentConfirmationAvailable(); + (await PaymentRequest.isSecurePaymentConfirmationAvailable()) === 'available'; if (!spcAvailable) { /* Browser does not support SPC; merchant should fallback to traditional flows. */ } @@ -658,15 +659,51 @@ A static API is added to {{PaymentRequest}} in order to provide developers a simplified method of checking whether Secure Payment Confirmation is available. +enum IsSecurePaymentConfirmationAvailableResult { + "available", + "unavailable-unknown-reason", + "unavailable-feature-not-enabled", + "unavailable-no-permission-policy", + "unavailable-no-user-verifying-platform-authenticator", +}; + partial interface PaymentRequest { - static Promise<boolean> isSecurePaymentConfirmationAvailable(); + static Promise<IsSecurePaymentConfirmationAvailableResult> isSecurePaymentConfirmationAvailable(); };
: {{PaymentRequest/isSecurePaymentConfirmationAvailable()}} - :: Upon invocation, a promise is returned that resolves with a value of - `true` if the Secure Payment Confirmation feature is available, or - `false` otherwise. + :: Upon invocation, a promise is returned that resolves with one of the + members of {{IsSecurePaymentConfirmationAvailableResult}}, based on the + current availability of the Secure Payment Confirmation feature. +
+
+ : available + :: Indicates that the user agent believes that the Secure Payment + Confirmation API is available in the calling frame. + + Note: This result does not indicate whether or not any particular [=SPC + credential=] is or will be available. + + : unavailable-unknown-reason + :: Indicates that the Secure Payment Confirmation API is not avaiable in + the calling frame, for an unknown reason. A user agent MAY always choose + to return this result instead of a more specific reason, in order to + protect user privacy. + + : unavailable-feature-not-enabled + :: Indicates that the Secure Payment Confirmation API is not available in + the calling frame, because the feature is not enabled. + + : unavailable-no-permission-policy + :: Indicates that the Secure Payment Confirmation API is not available in + the calling frame, because the frame lacks the "[=payment permission + string|payment=]" permission policy. + + : unavailable-no-user-verifying-platform-authenticator + :: Indicates that the Secure Payment Confirmation API is not available in + the calling frame, because there is no [=user-verifying platform + authenticator=] available.
This allows a developer to perform the following check when deciding whether to @@ -676,13 +713,16 @@ initiate a SPC flow: const spcAvailable = PaymentRequest && PaymentRequest.isSecurePaymentConfirmationAvailable && - await PaymentRequest.isSecurePaymentConfirmationAvailable(); + await PaymentRequest.isSecurePaymentConfirmationAvailable() === 'available'; NOTE: The use of the static {{PaymentRequest/isSecurePaymentConfirmationAvailable}} method is recommended for SPC feature detection, instead of calling {{PaymentRequest/canMakePayment}} on an already-constructed PaymentRequest object. +Note: For privacy considerations of this API, see + [[#sctn-fingerprinting-via-is-secure-payment-confirmation-available]]. + ### Steps to validate payment method data ### {#sctn-steps-to-validate-payment-method-data} The [=steps to validate payment method data=] for this payment method, for an @@ -1548,6 +1588,40 @@ they are strong, cross-site identifiers. However in order to obtain them from the [=Relying Party=], the merchant already needs an as-strong identifier to give to the [=Relying Party=] (e.g., the credit card number). +## Fingerprinting via isSecurePaymentConfirmationAvailable ## {#sctn-fingerprinting-via-is-secure-payment-confirmation-available} + +The {{isSecurePaymentConfirmationAvailable}} API presents a possible +fingerprinting risk, as it can silently return specific reasons that the +Secure Payment Confirmation API is not available for a specific frame. These +reasons are not believed to leak significant information, but should be +considered: + +- {{IsSecurePaymentConfirmationAvailableResult/unavailable-feature-not-enabled}}: + some risk of fingerprinting, depending on under what circumstances the user + agent considers Secure Payment Confirmation to be available or not. User + agents are encouraged to make Secure Payment Confirmation available to all + users (if implementing the specification), or at least to significantly + sized groups such that no (additional) fingerprinting is possible. For + example, a user agent may ship Secure Payment Confirmation to all users on + a given OS but not others - this then reduces the fingerprinting risk to + no more than the user agent string already reveals. +- {{IsSecurePaymentConfirmationAvailableResult/unavailable-no-permission-policy}}: + no (additional) fingerprinting risk, as the "[=payment permission + string|payment=]" permission policy is already silently detectable by + attempting to construct a {{PaymentRequest}} object (construction will throw + an error if the permission policy is not enabled). +- {{IsSecurePaymentConfirmationAvailableResult/unavailable-no-user-verifying-platform-authenticator}}: + no (additional) fingerprinting risk over the existing + {{PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable}} API. + +In addition to the above considerations, this specification allows a user agent +to choose to return +{{IsSecurePaymentConfirmationAvailableResult/unavailable-unknown-reason}} even +when a specific reason is known, should it wish to in order to preserve user +privacy. This might be done in the case, e.g., that a user agent has detected +that the current frame has already accessed other APIs that pose a +fingerprinting risk. + ## User opt out ## {#sctn-user-opt-out} The API option {{SecurePaymentConfirmationRequest/showOptOut}} tells the From f51441c3493ae4006452df7700136ba57738189e Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Tue, 11 Mar 2025 15:13:00 -0400 Subject: [PATCH 2/7] Rename API --- spec.bs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/spec.bs b/spec.bs index 7512c61..37c4a17 100644 --- a/spec.bs +++ b/spec.bs @@ -360,13 +360,13 @@ The sample code for authenticating the user follows. Note that the example code presumes access to await/async, for easier to read promise handling.
-/* isSecurePaymentConfirmationAvailable indicates whether the browser */
+/* securePaymentConfirmationAvailability indicates whether the browser */
 /* supports SPC. It does not indicate whether the user has a credential */
 /* ready to go on this device. */
 const spcAvailable =
   PaymentRequest &&
-  PaymentRequest.isSecurePaymentConfirmationAvailable &&
-  (await PaymentRequest.isSecurePaymentConfirmationAvailable()) === 'available';
+  PaymentRequest.securePaymentConfirmationAvailability &&
+  (await PaymentRequest.securePaymentConfirmationAvailability()) === 'available';
 if (!spcAvailable) {
   /* Browser does not support SPC; merchant should fallback to traditional flows. */
 }
@@ -659,7 +659,7 @@ A static API is added to {{PaymentRequest}} in order to provide developers a
 simplified method of checking whether Secure Payment Confirmation is available.
 
 
-enum IsSecurePaymentConfirmationAvailableResult {
+enum SecurePaymentConfirmationAvailability {
   "available",
   "unavailable-unknown-reason",
   "unavailable-feature-not-enabled",
@@ -668,16 +668,16 @@ enum IsSecurePaymentConfirmationAvailableResult {
 };
 
 partial interface PaymentRequest {
-    static Promise<IsSecurePaymentConfirmationAvailableResult> isSecurePaymentConfirmationAvailable();
+    static Promise<SecurePaymentConfirmationAvailability> securePaymentConfirmationAvailability();
 };
 
 
- : {{PaymentRequest/isSecurePaymentConfirmationAvailable()}} + : {{PaymentRequest/securePaymentConfirmationAvailability()}} :: Upon invocation, a promise is returned that resolves with one of the - members of {{IsSecurePaymentConfirmationAvailableResult}}, based on the + members of {{SecurePaymentConfirmationAvailability}}, based on the current availability of the Secure Payment Confirmation feature.
-
+
: available :: Indicates that the user agent believes that the Secure Payment Confirmation API is available in the calling frame. @@ -712,11 +712,11 @@ initiate a SPC flow:
 const spcAvailable =
     PaymentRequest &&
-    PaymentRequest.isSecurePaymentConfirmationAvailable &&
-    await PaymentRequest.isSecurePaymentConfirmationAvailable() === 'available';
+    PaymentRequest.securePaymentConfirmationAvailability &&
+    await PaymentRequest.securePaymentConfirmationAvailability() === 'available';
 
-NOTE: The use of the static {{PaymentRequest/isSecurePaymentConfirmationAvailable}} method is recommended for +NOTE: The use of the static {{PaymentRequest/securePaymentConfirmationAvailability}} method is recommended for SPC feature detection, instead of calling {{PaymentRequest/canMakePayment}} on an already-constructed PaymentRequest object. @@ -1588,15 +1588,15 @@ they are strong, cross-site identifiers. However in order to obtain them from the [=Relying Party=], the merchant already needs an as-strong identifier to give to the [=Relying Party=] (e.g., the credit card number). -## Fingerprinting via isSecurePaymentConfirmationAvailable ## {#sctn-fingerprinting-via-is-secure-payment-confirmation-available} +## Fingerprinting via securePaymentConfirmationAvailability ## {#sctn-fingerprinting-via-is-secure-payment-confirmation-available} -The {{isSecurePaymentConfirmationAvailable}} API presents a possible +The {{securePaymentConfirmationAvailability}} API presents a possible fingerprinting risk, as it can silently return specific reasons that the Secure Payment Confirmation API is not available for a specific frame. These reasons are not believed to leak significant information, but should be considered: -- {{IsSecurePaymentConfirmationAvailableResult/unavailable-feature-not-enabled}}: +- {{SecurePaymentConfirmationAvailability/unavailable-feature-not-enabled}}: some risk of fingerprinting, depending on under what circumstances the user agent considers Secure Payment Confirmation to be available or not. User agents are encouraged to make Secure Payment Confirmation available to all @@ -1605,18 +1605,18 @@ considered: example, a user agent may ship Secure Payment Confirmation to all users on a given OS but not others - this then reduces the fingerprinting risk to no more than the user agent string already reveals. -- {{IsSecurePaymentConfirmationAvailableResult/unavailable-no-permission-policy}}: +- {{SecurePaymentConfirmationAvailability/unavailable-no-permission-policy}}: no (additional) fingerprinting risk, as the "[=payment permission string|payment=]" permission policy is already silently detectable by attempting to construct a {{PaymentRequest}} object (construction will throw an error if the permission policy is not enabled). -- {{IsSecurePaymentConfirmationAvailableResult/unavailable-no-user-verifying-platform-authenticator}}: +- {{SecurePaymentConfirmationAvailability/unavailable-no-user-verifying-platform-authenticator}}: no (additional) fingerprinting risk over the existing {{PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable}} API. In addition to the above considerations, this specification allows a user agent to choose to return -{{IsSecurePaymentConfirmationAvailableResult/unavailable-unknown-reason}} even +{{SecurePaymentConfirmationAvailability/unavailable-unknown-reason}} even when a specific reason is known, should it wish to in order to preserve user privacy. This might be done in the case, e.g., that a user agent has detected that the current frame has already accessed other APIs that pose a From 549a3ca367e8b897864bee1fee51a4593f5c3956 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Tue, 15 Apr 2025 13:19:37 -0400 Subject: [PATCH 3/7] Make ordering specific --- spec.bs | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/spec.bs b/spec.bs index 37c4a17..0981e0a 100644 --- a/spec.bs +++ b/spec.bs @@ -671,12 +671,9 @@ partial interface PaymentRequest { static Promise securePaymentConfirmationAvailability(); }; -
- : {{PaymentRequest/securePaymentConfirmationAvailability()}} - :: Upon invocation, a promise is returned that resolves with one of the - members of {{SecurePaymentConfirmationAvailability}}, based on the - current availability of the Secure Payment Confirmation feature. -
+ +The {{SecurePaymentConfirmationAvailability}} enum contains the following members: +
: available :: Indicates that the user agent believes that the Secure Payment @@ -706,8 +703,33 @@ partial interface PaymentRequest { authenticator=] available.
-This allows a developer to perform the following check when deciding whether to -initiate a SPC flow: +Upon invocation of {{PaymentRequest/securePaymentConfirmationAvailability()}} +in a given {{Document}} |document|, the user agent must perform the below +steps. A user agent may at any time choose to return +"{{SecurePaymentConfirmationAvailability/unavailable-unknown-reason}}", if +needed to protect the privacy of the user or if a step cannot be completed for +a user-agent specific reason. + +1. If the user agent does not support Secure Payment Confirmation, or it does + support Secure Payment Confirmation but the feature is disabled via some + user-agent specific mechanism, return + "{{SecurePaymentConfirmationAvailability/unavailable-feature-not-enabled}}". + +1. If the "[=payment permission string|payment=]" permission policy is not + enabled for |document|, return + "{{SecurePaymentConfirmationAvailability/unavailable-no-permission-policy}}". + +1. If there is no [=user-verifying platform authenticator=] available, return + "{{SecurePaymentConfirmationAvailability/unavailable-no-user-verifying-platform-authenticator}}". + +1. If there is any other reason that the Secure Payment Confirmation feature + would not function if called in |document|, return + "{{SecurePaymentConfirmationAvailability/unavailable-unknown-reason}}". + +1. Return "{{SecurePaymentConfirmationAvailability/available}}". + +This API allows a developer to perform the following check when deciding +whether to initiate a SPC flow:
 const spcAvailable =

From 199583ed85c826bf415b4d85b2609448470aaa73 Mon Sep 17 00:00:00 2001
From: Stephen McGruer 
Date: Tue, 15 Apr 2025 13:23:37 -0400
Subject: [PATCH 4/7] Add note on isUserVerifyingPlatformAuthenticator

---
 spec.bs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/spec.bs b/spec.bs
index 0981e0a..80686e7 100644
--- a/spec.bs
+++ b/spec.bs
@@ -701,6 +701,10 @@ The {{SecurePaymentConfirmationAvailability}} enum contains the following member
     ::  Indicates that the Secure Payment Confirmation API is not available in
         the calling frame, because there is no [=user-verifying platform
         authenticator=] available.
+
+        Note: This information can also be obtained by calling
+              {{PublicKeyCredential/isUserVerifyingPlatformAuthenticatorAvailable}},
+              but is included as part of this API for developer ergonomics.
 
Upon invocation of {{PaymentRequest/securePaymentConfirmationAvailability()}} From b53046f979715511d446e26e2fc8c9ee6fed0571 Mon Sep 17 00:00:00 2001 From: Stephen McGruer Date: Tue, 15 Apr 2025 13:27:25 -0400 Subject: [PATCH 5/7] Add blurb --- spec.bs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec.bs b/spec.bs index 80686e7..2f63159 100644 --- a/spec.bs +++ b/spec.bs @@ -657,6 +657,11 @@ The [=payment method additional data type=] for this payment method is A static API is added to {{PaymentRequest}} in order to provide developers a simplified method of checking whether Secure Payment Confirmation is available. +This method, {{PaymentRequest/securePaymentConfirmationAvailability()}}, +returns a member of an enum either indicating that Secure Payment Confirmation +is available, or that it is unavailable with some indication as to the +underlying reason. The use of an enum output is intended to aid developers in +guiding and messaging to users with regards to their authentication options. enum SecurePaymentConfirmationAvailability { From 8acc3506e6b3599959f530f4b0369ae79f687e1a Mon Sep 17 00:00:00 2001 From: Stephen McGruer <smcgruer@chromium.org> Date: Tue, 15 Apr 2025 13:54:10 -0400 Subject: [PATCH 6/7] Update spec.bs Co-authored-by: ianbjacobs <ij@w3.org> --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index 2f63159..d8e84ac 100644 --- a/spec.bs +++ b/spec.bs @@ -688,7 +688,7 @@ The {{SecurePaymentConfirmationAvailability}} enum contains the following member credential=] is or will be available. : <dfn>unavailable-unknown-reason</dfn> - :: Indicates that the Secure Payment Confirmation API is not avaiable in + :: Indicates that the Secure Payment Confirmation API is not available in the calling frame, for an unknown reason. A user agent MAY always choose to return this result instead of a more specific reason, in order to protect user privacy. From 430e77c43dd0e43c700feb92663ef53dc74682ee Mon Sep 17 00:00:00 2001 From: Stephen McGruer <smcgruer@chromium.org> Date: Tue, 15 Apr 2025 13:54:21 -0400 Subject: [PATCH 7/7] Update spec.bs Co-authored-by: ianbjacobs <ij@w3.org> --- spec.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec.bs b/spec.bs index d8e84ac..0259fda 100644 --- a/spec.bs +++ b/spec.bs @@ -1635,7 +1635,7 @@ considered: sized groups such that no (additional) fingerprinting is possible. For example, a user agent may ship Secure Payment Confirmation to all users on a given OS but not others - this then reduces the fingerprinting risk to - no more than the user agent string already reveals. + no more than what the user agent string already reveals. - {{SecurePaymentConfirmationAvailability/unavailable-no-permission-policy}}: no (additional) fingerprinting risk, as the "[=payment permission string|payment=]" permission policy is already silently detectable by