1. Introduction
This section and its sub-sections are non-normative.
This specification defines an API that enables the use of strong authentication methods in payment flows on the web. It aims to provide the same authentication benefits and user privacy focus as [webauthn-3] with enhancements to meet the needs of payment processing.
Similarly to [webauthn-3] , this specification defines two related processes involving a user. The first is § 3 Registration (formerly "enrollment"), where a relationship is created between the user and the Relying Party . The second is § 4 Authentication , where the user responds to a challenge from the Relying Party (possibly via an intermediary payment service provider) to consent to a specific payment.
It is a goal of this specification to reduce authentication friction during checkout, and one aspect of that is to maximize the number of authentications that the user can perform for a given registration. That is, with consent from the Relying Party , ideally the user could "register once" and authenticate on any merchant origin (and via payment service provider), not just the merchant origin where the user first registered.
To that end, an important feature of Secure Payment Confirmation is that the merchant (or another entity) may initiate the authentication ceremony on the Relying Party’s behalf. The Relying Party must opt-in to allowing this behavior during credential creation.
Functionally,
this
specification
defines
a
new
payment
method
for
the
PaymentRequest
API,
and
adds
a
WebAuthn
Extension
to
extend
[webauthn-3]
with
payment-specific
datastructures
datastructures,
device
binding
and
to
relax
assumptions
to
allow
the
API
to
be
called
in
payment
contexts.
1.1. Use Cases
Although [webauthn-3] provides general authentication capabilities for the Web, the following use cases illustrate the value of the payment-specific extension defined in this specification.
We presume that the general use case of cryptographic-based authentication for online transactions is well established.
1.1.1. Cryptographic evidence of transaction confirmation
In many online payment systems, it is common for the entity (e.g., bank) that issues a payment instrument to seek to reduce fraud through authentication. [webauthn-3] and this specification make it possible to use authenticators to cryptographically sign important payment-specific information such as the origin of the merchant and the transaction amount and currency. The bank, as the Relying Party , can then verify the signed payment-specific information as part of the decision to authorize the payment.
If
the
bank
uses
plain
[webauthn-3]
,
the
payment-specific
information
to
be
verified
must
be
stored
in
the
WebAuthn
challenge
.
This
raises
several
issues:
-
It is a misuse of the
challengefield (which is intended to defeat replay attacks). -
There is no specification for this, so each bank is likely to have to devise its own format for how payment-specific information should be formatted and encoded in the challenge, complicating deployment and increasing fragmentation.
-
Regulations may require evidence that the user was shown and agreed to the payment-specific information. Plain [webauthn-3] does not provide for this display: there is no specified UX associated with information stored in the
challengefield.
These limitations motivate the following Secure Payment Confirmation behaviors:
-
The
challengefield is only used to defeat replay attacks, as with plain [webauthn-3] . -
SPC specifies a format for payment-specific information. This will enable development of generic verification code and test suites.
-
SPC guarantees that the user agent has presented the payment-specific information to the user in a way that a malicious website (or maliciously introduced JavaScript code on a trusted website) cannot bypass.
-
The payment-specific information is included in the
CollectedClientDatadictionary, which cannot be tampered with via JavaScript.
NOTE: Banks and other stakeholders in the payments ecosystem trust payments via browsers sufficiently today using TLS, iframes, and other Web features. The current specification is designed to increase the security and usability of Web payments.
-
1.1.2. Merchant control of authentication
Merchants seek to avoid user drop-off during checkout, in particular by reducing authentication friction. A Relying Party (e.g., a bank) that wishes to use [webauthn-3] to authenticate the user typically does so from an iframe. However, merchants would prefer to manage the user experience of authenticating the user while still enabling the Relying Party to verify the results of authentication.
This limitation motivates the following Secure Payment Confirmation behavior:
-
With SPC, other parties than the Relying Party can use authentication credentials on behalf of the Relying Party. The Relying Party can then verify the authentication results.
An additional benefit of this feature to Relying Parties is that they no longer need to build their own front-end experiences for authentication. Instead, payment service providers are likely to build them on behalf of merchants.
NOTE: Relying Parties that wish to provide the authentication user experience may still do so using SPC from an iframe.
1.1.3. Cryptographic evidence of device binding
In the payments industry a signal of device possession plays an important role as a second factor. WebAuthn allows for synced passkeys where one credential is available on multiple devices ( Web Authentication § 1.2.1 Consumer with Multi-Device Credentials ). Although syncing improves the user experience for login use cases, concerns have been raised that synced passkeys alone do not satisfy device possession requirements in some regulatory environments.
These concerns motivate the inclusion of auxiliary public private key pairs created by the user agent where the private key only resides on (and is used on) one device. Such a key and its use in SPC is referred to as a browser bound key .
1.2. Sample API Usage Scenarios
In this section, we walk through some scenarios for Secure Payment Confirmation and the corresponding sample code for using this API. Note that these are example flows and do not limit the scope of how the API can be used.
1.2.1. Registration during a checkout
This is a first-time flow, in which a new credential is created and stored by an issuing bank during a checkout by the user on some merchant.
-
The user visits
merchant.com, selects an item to purchase, and proceeds to the checkout flow. They enter their payment instrument details, and indicate that they wish to pay (e.g., by pressing a "Pay" button). -
The merchant communicates out-of-band (e.g., using another protocol) with the bank that issued the payment instrument. The issuing bank requests verification of the user, and provides a bank-controlled URL for the merchant to open in an iframe.
-
The merchant opens an iframe to
bank.com, with theallowattribute set to " publickey-credentials-create ". -
In the iframe, the issuing bank confirms the user’s identity via a traditional means (e.g., SMS OTP). After confirmation, the bank invites the user to register in SPC authentication for future payments.
-
The user consents (e.g., by clicking an "Register" button in the bank UX), and the bank runs code in the iframe (see example below).
-
The user goes through a WebAuthn registration flow. A new credential is created and returned to the issuing bank who stores it in their server-side database associated with the user and payment instrument(s).
-
The verification completes; the bank iframe closes and the merchant finishes the checkout process for the user.
Sample code for registering the user in this way follows:
if ( ! window. PublicKeyCredential) { /* Client not capable. Handle error. */ } const publicKey= { // The challenge should be created by the bank server and sent to the iframe. challenge: new Uint8Array([ 21 , 31 , 105 /* 29 more random bytes generated by the server */ ]), // Relying Party: rp: { name: "Fancy Bank" , }, // User: user: { // Part of WebAuthn. This information is not required by SPC // but may be used by the bank server to identify this user in // future transactions. Inconsistent values for the same user // can result in the creation of multiple credentials for the user // and thus potential UX friction due to credential selection. id: Uint8Array. from ( window. atob( "MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII=" ), c=> c. charCodeAt( 0 )), name: "jane.doe@example.com" , displayName: "Jane Doe" , }, // In this example the Relying Party accepts either an ES256 or RS256 // credential, but prefers an ES256 credential. pubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" }, { type: "public-key" , alg: - 257 // "RS256" } ], authenticatorSelection: { userVerification: "required" , residentKey: "required" , authenticatorAttachment: "platform" , }, timeout: 360000 , // 6 minutes // Indicate that this is an SPC credential. This is currently required so // that the browser knows this credential relates to SPC. It also enables // credential creation in a cross-origin iframe, which is required for this // example. // // A future version of the spec may remove the need for this extension. extensions: { "payment" : { isPayment: true , // An optional list of allowed algorithms. When not present or empty, the // pubKeyCredparams are used defaulting to ES256 and RS256. In this // example ES256 and RS256 are allowed and RS256 is preferred. browserBoundPubKeyCredParams: [ { type: "public-key" , alg: - 257 // "RS256" }, { type: "public-key" , alg: - 7 // "ES256" } ] } } }; // Note: The following call will cause the authenticator to display UI. navigator. credentials. create({ publicKey}) . then( function ( newCredentialInfo) { // Send new credential info to server for verification and registration. }). catch ( function ( err) { // No acceptable authenticator or user refused consent. Handle appropriately. });
1.2.2. Authentication on merchant site
This is the flow when a user with an already registered credential is performing a transaction and the issuing bank and merchant wish to use Secure Payment Confirmation.
-
The user visits
merchant.com, selects an item to purchase, and proceeds to the checkout flow. They enter their payment instrument details, and indicate that they wish to pay (e.g., by pressing a "Pay" button). -
The merchant communicates out-of-band with the issuing bank of the payment instrument (e.g., using another protocol). The issuing bank requests verification of the user, and at the same time informs the merchant that it accepts SPC by providing the information necessary to use the API. This information includes a challenge and any credential IDs associated with this user and payment instrument(s).
-
The merchant runs the example code shown below.
-
The user agrees to the payment-specific information displayed in the SPC UX, and performs a subsequent WebAuthn authentication ceremony. The signed cryptogram is returned to the
merchant.merchant (including browser bound key outputs inAuthenticationExtensionsPaymentOutputs). -
The merchant communicates the signed cryptogram to the issuing bank out-of-band. The issuing bank verifies the cryptogram, and knows that the user is valid, what payment-specific information has been displayed, and that the user has consented to the transaction. The issuing bank authorizes the transaction and the merchant finishes the checkout process for the user. The issuing bank stores the browser bound key ’s public key,
browserBoundPublicKey.
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 */ /* 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(); if ( ! spcAvailable) { /* Browser does not support SPC; merchant should fallback to traditional flows. */ } const request= new PaymentRequest([{ supportedMethods: "secure-payment-confirmation" , data: { // List of credential IDs obtained from the bank. credentialIds, rpId: "fancybank.com" , // The challenge is also obtained from the bank. challenge: new Uint8Array([ 21 , 31 , 105 /* 29 more random bytes generated by the bank */ ]), instrument: { displayName: "Fancy Card ****1234" , icon: "https://fancybank.com/card-art.png" , }, payeeName: "Merchant Shop" , payeeOrigin: "https://merchant.com" , // Caller’s requested localized experience localelocale: [ "en" ], timeout: 360000 , // 6 minutes // An optional list of allowed algorithms defaulting to ES256 and RS256. // In this example ES256 and RS256 are allowed and ES256 is preferred. // Browser bound keys are not created when already present, so this // list is only used when the browser bound key does need to be // created. browserBoundPubKeyCredParams: [ { type: "public-key" , alg: - 7 // "ES256" }, { type: "public-key" , alg: - 257 // "RS256" } ] }], { total: { label: "Total" , amount: { currency: "USD" , value: "5.00" , }, }, }); try { const response= await request. show(); await response. complete( 'success' ); // response.data is a PublicKeyCredential, with a clientDataJSON that // contains the transaction data for verification by the issuing bank. /* send response.data to the issuing bank for verification */ } catch ( err) { /* SPC cannot be used; merchant should fallback to traditional flows */ }
2. Terminology
- SPC Credential
-
A WebAuthn credential that can be used for the behaviors defined in this specification.
This specification does not intend to limit how SPC credentials may (or may not) be used by a Relying Party for other authentication flows (e.g., login).
Note: The current version of this specification requires the Relying Party to explicitly opt in for a credential to be used in either a first-party or third-party context. Longer-term, our intention is that all WebAuthn credentials will be usable for SPC in a first-party context (e.g., on the Relying Party’s domain) and opt-in will only be required to allow a credential to be used by a third-party.
- Third-party enabled SPC Credential
-
An SPC Credential where the Relying Party has explicitly opted in at credential creation time to allow use of the credential in a Secure Payment Confirmation authentication by a party other than the Relying Party .
- Steps to silently determine if an SPC Credential is third-party enabled
-
An as-yet undefined process by which a user agent can, given a Relying Party Identifier and a credential ID , silently (i.e., without user interaction) determine if the credential represented by that ID is a third-party enabled SPC Credential .
NOTE: See WebAuthn issue 1667 .
- Steps to silently determine if a credential is available for the current device
-
An as-yet undefined process by which a user agent can, given a Relying Party Identifier and a credential ID , silently (i.e., without user interaction) determine if the credential represented by that credential ID is available for the current device (i.e., could be successfully used as part of a WebAuthn Get call).
This allows the user agent to only conditionally display the transaction UX to the user if there is some chance that they can successfully complete the transaction.
NOTE: This property will likely require that SPC Credentials be discoverable ; as such this specification currently encodes that as a requirement.
NOTE: This property is very similar to that which is required for the WebAuthn Conditional UI Proposal . It is likely that both it and SPC could be supported by the same underlying API.
- Browser bound key
A public-private key pair that signs over the transaction details in addition to the WebAuthn credential and is tied to a single device by the user agent.
- Key Pair
A pair of asymmetric cryptographic keys. These are algorithm specific parameters to the cryptographic algorithms referenced by the IANA COSE Algorithms registry [IANA-COSE-ALGS-REG] .
The public key portion is returned during registration in
CollectedClientAdditionalPaymentRegistrationData.browserBoundPublicKeyand during payment assertion inCollectedClientAdditionalPaymentData.browserBoundPublicKey.The private key portion is used to generate cryptographic signatures included in
BrowserBoundSignature.signature. The user agent does not export the private key and may store the private key in a secure element of the device.
3. Registration
To
register
a
user
for
Secure
Payment
Confirmation,
relying
parties
should
call
navigator.credentials.create()
,
with
the
payment
WebAuthn
Extension
specified.
Tests
Note: In this specification we define an extension in order to allow the browser to cache SPC credential IDs in the absence of Conditional UI . If this capability is available in future versions of WebAuthn, we may remove the requirement for the extension from SPC. Note that SPC credentials (with the extension) are otherwise full-fledged WebAuthn credentials.
Note:
At
registration
time,
Web
Authentication
requires
both
name
and
displayName
,
although
per
the
definition
of
the
user
member
,
implementations
are
not
required
to
display
either
of
them
in
subsequent
authentication
ceremonies.
Of
the
two,
as
of
October
2023
name
is
shown
more
consistently.
Developers
should
continue
to
monitor
implementations.
4. Authentication
To authenticate a payment via Secure Payment Confirmation, this specification defines a new payment method , " secure-payment-confirmation ". This payment method confirms the transaction with the user and then performs an authentication ceremony to authenticate the user and create a signed blob representing the authentication ceremony.
At a high level, authentication for Secure Payment Confirmation is similar to [webauthn-3] , with one major conceptual shift. Secure Payment Confirmation allows a third-party (e.g., the merchant) to trigger an authentication ceremony on behalf of the Relying Party , passing in credentials that it has obtained from the Relying Party on some other unspecified channel. See § 1.1.2 Merchant control of authentication .
4.1. Payment Method: Secure Payment Confirmation
This specification defines a new payment handler , the Secure Payment Confirmation payment handler , which handles requests to authenticate a given payment.
NOTE: To quickly support an initial SPC experiment, this API was designed atop existing implementations of the Payment Request and Payment Handler APIs. There is now general agreement to explore a design of SPC independent of Payment Request. We therefore expect (without a concrete timeline) that SPC will move away from its Payment Request origins. For developers, this should improve feature detection, invocation, and other aspects of the API.
4.1.1. Payment Method Identifier
The standardized payment method identifier for the Secure Payment Confirmation payment handler is " secure-payment-confirmation ".
4.1.2. Registration in [payment-method-id]
Add the following to the registry of standardized payment methods in [payment-method-id] :
- " secure-payment-confirmation "
-
The Secure Payment Confirmation specification.
4.1.3. Modification of Payment Request constructor
In
the
steps
for
the
PaymentRequest
object’s
constructor
,
add
a
new
step
after
step
4.3:
-
Process payment methods: [substeps 1-3 elided]
-
If seenPMIs contains " secure-payment-confirmation " and the size of seenPMIs is greater than 1, throw a
RangeError.
-
4.1.4. Modification of user activation requirement
In
the
steps
for
the
PaymentRequest.show()
method,
modify
steps
2
and
3:
-
If the relevant global object of request does not have transient activation , the user agent MAY:
-
Return a promise rejected with with a
"SecurityError"DOMException.
-
-
Otherwise, consume user activation of the relevant global object .
NOTE:
This
allows
the
user
agent
to
not
require
user
activation,
for
example
to
support
redirect
authentication
flows
where
a
user
activation
may
not
be
present
upon
redirect.
See
§ 10.3
§ 11.3
Lack
of
user
activation
requirement
for
security
considerations.
4.1.5.
SecurePaymentConfirmationRequest
Dictionary
dictionary SecurePaymentConfirmationRequest {required BufferSource challenge ;required USVString rpId ;required sequence <BufferSource >credentialIds ;required PaymentCredentialInstrument instrument ;unsigned long timeout ;USVString payeeName ;USVString payeeOrigin ;AuthenticationExtensionsClientInputs extensions ;;sequence <PublicKeyCredentialParameters >browserBoundPubKeyCredParams ;sequence <USVString >locale ;boolean showOptOut ; };
The
SecurePaymentConfirmationRequest
dictionary
contains
the
following
members:
-
challengemember, of type BufferSource -
A random challenge that the relying party generates on the server side to prevent replay attacks.
-
rpIdmember, of type USVString -
The Relying Party Identifier of the credentials.
-
credentialIdsmember, of type sequence< BufferSource > -
The list of credential identifiers for the given instrument.
-
instrumentmember, of type PaymentCredentialInstrument -
The description of the instrument name and icon to display during registration and to be signed along with the transaction details.
-
timeoutmember, of type unsigned long -
The number of milliseconds before the request to sign the transaction details times out. At most 1 hour. Default values and the range of allowed values is defined by the user agent. Web Authentication provides additional timeout guidance .
-
payeeNamemember, of type USVString -
The display name of the payee that this SPC call is for (e.g., the merchant). Optional, may be provided alongside or instead of
payeeOrigin. -
payeeOriginmember, of type USVString -
The origin of the payee that this SPC call is for (e.g., the merchant). Optional, may be provided alongside or instead of
payeeName. -
extensionsmember, of type AuthenticationExtensionsClientInputs -
Any WebAuthn extensions that should be used for the passed credential(s). The caller does not need to specify the payment extension ; it is added automatically.
-
browserBoundPubKeyCredParamsmember, of type sequence< PublicKeyCredentialParameters > The list of allowed types of credential restricting the types of cryptographic algorithms used for the browser bound key.
Note: This member will be used only if a browser bound key will need to be created.
-
localemember, of type sequence< USVString > -
An optional list of well-formed [BCP47] language tags, in descending order of priority, that identify the locale preferences of the website, i.e. a language priority list [RFC4647] , which the user agent can use to perform language negotiation and locale-affected formatting with the caller.
NOTE: The
localeis distinct from language or direction metadata associated with specific input members, in that it represents the caller’s requested localized experience rather than assertion about a specific string value. See§ 13§ 14 Internationalization Considerations for more discussion. -
showOptOutmember, of type boolean -
Whether the user should be given a chance to opt-out during the transaction confirmation UX . Optional, default false.
4.1.6. Payment Method additional data type
The
payment
method
additional
data
type
for
this
payment
method
is
SecurePaymentConfirmationRequest
.
4.1.7. Checking if Secure Payment Confirmation is available
A
static
API
is
added
to
PaymentRequest
in
order
to
provide
developers
a
simplified
method
of
checking
whether
Secure
Payment
Confirmation
is
available.
partial interface PaymentRequest {static Promise <boolean >(); };isSecurePaymentConfirmationAvailable
-
isSecurePaymentConfirmationAvailable() -
Upon invocation, a promise is returned that resolves with a value of
trueif the Secure Payment Confirmation feature is available, orfalseotherwise.
This allows a developer to perform the following check when deciding whether to initiate a SPC flow:
const spcAvailable= PaymentRequest&& PaymentRequest. isSecurePaymentConfirmationAvailable&& await PaymentRequest. isSecurePaymentConfirmationAvailable();
NOTE:
The
use
of
the
static
isSecurePaymentConfirmationAvailable
method
is
recommended
for
SPC
feature
detection,
instead
of
calling
canMakePayment
on
an
already-constructed
PaymentRequest
object.
4.1.8. Steps to validate payment method data
The
steps
to
validate
payment
method
data
for
this
payment
method,
for
an
input
PaymentRequest
request
and
SecurePaymentConfirmationRequest
data
,
are:
Tests
-
If data ["
credentialIds"] is empty, throw aRangeError. -
For each id in data ["
credentialIds"]:-
If id is empty, throw a
RangeError.
-
-
If data ["
challenge"] is null or empty, throw aTypeError. -
If data ["
instrument"]["displayName"] is empty, throw aTypeError. -
If data ["
instrument"]["icon"] is empty, throw aTypeError. -
Run the URL parser on data["
instrument"] ["icon"]. If this returns failure, throw aTypeError. -
If data ["
rpId"] is not a valid domain , throw aTypeError. -
If both data ["
payeeName"] and data ["payeeOrigin"] are omitted, throw aTypeError. -
If either of data ["
payeeName"] or data ["payeeOrigin"] is present and empty, throw aTypeError. -
If data ["
payeeOrigin"] is present:-
Let parsedURL be the result of running the URL parser on data ["
payeeOrigin"]. -
If parsedURL is failure, then throw a
TypeError. -
If parsedURL ’s scheme is not "
https", then throw aTypeError.
-
4.1.9. Steps to check if a payment can be made
The
steps
to
check
if
a
payment
can
be
made
for
this
payment
method,
for
an
input
SecurePaymentConfirmationRequest
data
,
are:
Tests
-
If data ["
payeeOrigin"] is present:-
Let parsedURL be the result of running the URL parser on data ["
payeeOrigin"]. -
Assert that parsedURL is not failure.
-
Assert that parsedURL ’s scheme is "
https".
NOTE: These pre-conditions were previously checked in the steps to validate payment method data .
-
Set data ["
payeeOrigin"] to the serialization of parsedURL ’s origin .
-
-
Fetch the image resource for the icon, passing «["
src" → data ["instrument"]["icon"]]» for image . If this fails:-
If data ["
instrument"]["iconMustBeShown"] istrue, then returnfalse. -
Otherwise, set data ["
instrument"]["icon"] to an empty string.Note: This lets the RP know that the specified icon was not shown, as the output
instrumentwill have an empty icon string.
Note: The image resource must be fetched whether or not any credential matches, to defeat attempts to probe for credential existence .
-
-
For each id in data ["
credentialIds"]:-
Run the steps to silently determine if a credential is available for the current device , passing in data ["
rpId"] and id . If the result isfalse, remove id from data ["credentialIds"]. -
If the data ["
rpId"] is not the origin of the relevant settings object of request , run the steps to silently determine if an SPC Credential is third-party enabled , passing in data ["rpId"] and id . If the result isfalse, remove id from data ["credentialIds"].
-
-
If data ["
credentialIds"] is now empty, returnfalse. The user agent must maintain authentication ceremony privacy and not leak this lack of matching credentials to the caller, by:-
Not allowing the caller to perform a timing attack on this outcome versus the user declining to authenticate on the transaction confirmation UX , e.g., by presenting an alternative interstitial that the user must interact with.
-
Rejecting the
show()promise with a "NotAllowedError"DOMException.
-
-
Return
true.
4.1.10. Displaying a transaction confirmation UX
To
avoid
restricting
User
Agent
implementation
choice,
this
specification
does
not
require
a
User
Agent
to
display
a
particular
user
interface
when
PaymentRequest.show()
is
called
and
the
Secure
Payment
Confirmation
payment
handler
is
selected.
However,
so
that
a
Relying
Party
can
trust
the
information
included
in
CollectedClientPaymentData
,
the
User
Agent
MUST
ensure
that
the
following
is
communicated
to
the
user
and
that
the
user’s
consent
is
collected
for
the
authentication:
-
The
payeeNameif it is present. -
The
payeeOriginif it is present. -
The
total, that is thecurrencyandvalueof the transaction. -
The
instrumentdetails, that is the payment instrumentdisplayNameandicon. If an image resource could not be fetched or decoded from the inputicon, then the User Agent may show no icon or a generic payment instrument icon in its place.NOTE: If the specified icon could not be fetched or decoded, then
iconMustBeShownmust befalsehere as otherwise the the steps to check if a payment can be made would have failed previously.
The
user
agent
MAY
utilize
the
information
in
locale
,
if
any,
to
display
a
UX
localized
into
a
language
and
using
locale-based
formatting
consistent
with
that
of
the
website.
If
showOptOut
is
true
,
the
user
agent
MUST
give
the
user
the
opportunity
to
indicate
that
they
want
to
opt
out
of
the
process
for
the
given
relying
party
.
If
the
user
indicates
that
they
wish
to
opt-out,
then
the
user
agent
must
reject
the
show()
promise
with
an
"
OptOutError
"
DOMException
.
See
§ 11.4
§ 12.4
User
opt
out
.
If
the
current
transaction
automation
mode
is
not
"
none
",
the
user
agent
should
first
verify
that
it
is
in
an
automation
context
(see
WebDriver’s
Security
considerations
).
The
user
agent
should
then
bypass
the
above
communication
of
information
and
gathering
of
user
consent,
and
instead
do
the
following
based
on
the
value
of
the
current
transaction
automation
mode
:
-
"
autoAccept" -
Act as if the user has seen the transaction details and accepted the authentication.
-
"
autoReject" -
Act as if the user has seen the transaction details and rejected the authentication.
-
"
autoOptOut" -
Act as if the user has seen the transaction details and indicated they want to opt out.
4.1.11. Steps to respond to a payment request
The
steps
to
respond
to
a
payment
request
for
this
payment
method,
for
a
given
PaymentRequest
request
and
SecurePaymentConfirmationRequest
data
,
are:
-
Let topOrigin be the top-level origin of the relevant settings object of request .
-
Let payment be a new a
AuthenticationExtensionsPaymentInputsdictionary, whose fields are:-
isPayment -
The boolean value
true. -
rpId -
data ["
rpId"] -
topOrigin -
topOrigin
-
payeeName -
data ["
payeeName"] if it is present, otherwise omitted. -
payeeOrigin -
data ["
payeeOrigin"] if it is present, otherwise omitted. -
total -
request . [[details]] ["
total"] -
instrument -
data ["
instrument"] -
browserBoundPubKeyCredParams data ["
browserBoundPubKeyCredParams"]
-
-
Let extensions be a new
AuthenticationExtensionsClientInputsdictionary whosepaymentmember is set to payment , and whose other members are set from data ["extensions"]. -
Let publicKeyOpts be a new
PublicKeyCredentialRequestOptionsdictionary, whose fields are:-
challenge -
data ["
challenge"] -
timeout -
data ["
timeout"] -
rpId -
data ["
rpId"] -
userVerification -
extensions -
extensions
Note: This algorithm hard-codes "required" as the value for
userVerification, because that is what Chrome’s initial implementation supports. The current limitations may change. The Working Group invites implementers to share use cases that would benefit from support for other values (e.g., "preferred" or "discouraged"). -
-
For each id in data ["
credentialIds"]:-
Let descriptor be a new
PublicKeyCredentialDescriptordictionary, whose fields are:-
type -
id -
id
-
transports -
A sequence of length 1 whose only member is
internal.
-
-
Append descriptor to publicKeyOpts ["
allowCredentials"].
-
-
Let outputCredential be the result of running the algorithm to Request a Credential , passing «["
publicKey" → publicKeyOpts ]».Note: Chrome’s initial implementation does not pass the full
data.credentialIdslist to Request a Credential . Instead, it chooses one credential in the list that matches the current device and passes only that in.Note: This triggers [webauthn-3] ’s Get behavior
-
Return outputCredential .
5.
WebAuthn
Extension
-
"
payment
"
This client registration extension and authentication extension indicates that a credential is either being created for or used for Secure Payment Confirmation, respectively.
For registration, this extension allows the browser to identify and cache Secure Payment Confirmation credential IDs. For authentication, this extension allows a third-party to perform an authentication ceremony on behalf of the Relying Party , and also adds transaction information to the signed cryptogram.
Notably,
a
website
should
not
call
navigator.credentials.get()
with
this
extension
directly;
for
authentication
the
extension
can
only
be
accessed
via
PaymentRequest
with
a
"
secure-payment-confirmation
"
payment
method.
Note:
Previously,
the
payment
extension
allowed
for
the
creation
of
credentials
in
a
cross-origin
iframe.
However
that
behavior
is
now
allowed
in
WebAuthn
by
default,
as
of
WebAuthn
PR
#1801
.
Tests
This test does not directly correspond to a spec line, but instead tests that authentication can be triggered from inside a cross-origin iframe. That behavior is specified by the lack of any line forbidding it.
- Extension identifier
-
payment - Operation applicability
- Client extension input
-
partial dictionary AuthenticationExtensionsClientInputs {AuthenticationExtensionsPaymentInputs ; };payment dictionary {AuthenticationExtensionsPaymentInputs boolean isPayment ;sequence <PublicKeyCredentialParameters >browserBoundPubKeyCredParams ; // Only used for authentication.USVString rpId ;USVString topOrigin ;USVString payeeName ;USVString payeeOrigin ;PaymentCurrencyAmount total ;PaymentCredentialInstrument instrument ; };-
isPaymentmember, of type boolean -
Indicates that the extension is active.
-
rpIdmember, of type USVString -
The Relying Party id of the credential(s) being used. Only used at authentication time; not registration.
-
topOriginmember, of type USVString -
The origin of the top-level frame. Only used at authentication time; not registration.
-
payeeNamemember, of type USVString -
The payee name, if present, that was displayed to the user. Only used at authentication time; not registration.
-
payeeOriginmember, of type USVString -
The payee origin, if present, that was displayed to the user. Only used at authentication time; not registration.
-
totalmember, of type PaymentCurrencyAmount -
The transaction amount that was displayed to the user. Only used at authentication time; not registration.
-
instrumentmember, of type PaymentCredentialInstrument -
The instrument details that were displayed to the user. Only used at authentication time; not registration.
-
browserBoundPubKeyCredParamsmember, of type sequence< PublicKeyCredentialParameters > The list of allowed types of credential restricting the types of cryptographic algorithms used for the browser bound key.
Note: When this member is not present, it defaults to
PublicKeyCredentialCreationOptions.pubKeyCredParams.
-
- Client extension processing ( registration )
-
When creating a new credential :
-
After step 3, insert the following step:
-
If any of the following are true:
-
pkOptions ["
authenticatorSelection"]["authenticatorAttachment"] is not "platform". -
pkOptions ["
authenticatorSelection"]["residentKey"] is not "required" or "preferred". -
pkOptions ["
authenticatorSelection"]["userVerification"] is not "required".
then throw a
TypeError.Note: These values are hard-coded as that is what Chrome’s initial implementation supports. The current limitations may change. The Working Group invites implementers to share use cases that would benefit from support for other values.
-
-
-
Before step 13 (creating a
CollectedClientData).Let bbk_allowed_algorithms be
browserBoundPubKeyCredParams.If
browserBoundPubKeyCredParamsis empty, let bbk_allowed_algorithms bePublicKeyCredentialCreationOptions.pubKeyCredParams.Let bbk_and_algorithm , bbk_id be the result of creating a key pair using bbk_allowed_algorithms .
If the result of creating a key pair is null, skip the steps below relating to bbk_and_algorithm and bbk_public_key .
Let bbk_public_key be the result of getting a browser bound public key using bbk_and_algorithm .
In step 13, instead of creating the
CollectedClientDatacreate aCollectedClientPaymentDatawhose fields are:paymentset to aCollectedClientAdditionalPaymentRegistrationDatawithbrowserBoundPublicKeybbk_public_key - The COSE_Key encoded public key.
All other fields set as per the original step 13.
In step 22 , case "any authenticator indicates success", step 3, just before returning pubKeyCred :
Bind a key pair using bbk_id and pubKeyCred .
[[identifier]].If binding a key pair failed, return an error,
UnknownError.Let payment_outputs be
AuthenticationExtensionsPaymentOutputswith:browserBoundSignatureA
BrowserBoundSignaturewith fields:signatureResult of generating a browser bound signature using bbk_and_algorithm and clientDataJson from create credential step 14.
Set "payment" → payment_outputs on the
[[clientExtensionsResults]].
-
- Client extension processing ( authentication )
-
When making an assertion with a
AuthenticationExtensionsPaymentInputsextension_inputs :-
If not in a " secure-payment-confirmation " payment handler, return a "
NotAllowedError"DOMException.Note: This guards against websites trying to access the extended powers of SPC without going through the transaction UX .
-
During
[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors):-
Skip step 6.1, which compares options.rpId to effectiveDomain
Note: This enables cross-domain authentication ceremonies; see § 1.1.2 Merchant control of authentication .
-
Before step 10, before creating a
CollectedClientData.Let allowed_algorithms be the
SecurePaymentConfirmationRequest.browserBoundPubKeyCredParams.Let bbk_and_algorithm be the result of getting or creating a browser bound key using credential_id and allowed_algorithms .
If bbk_and_algorithm is null, do not include the
browserBoundPublicKeyin subsequent steps.
In step
9,10, instead of creating aCollectedClientData, instead create aCollectedClientPaymentDatawith:-
typeset to "payment.get" -
paymentset to a newCollectedClientAdditionalPaymentDatawhose fields are:-
rpId -
extension_inputs ["
rpId"] -
topOrigin -
extension_inputs ["
topOrigin"] -
payeeName -
extension_inputs ["
payeeName"] if it is present, otherwise omitted. -
payeeOrigin -
extension_inputs ["
payeeOrigin"] if it is present, otherwise omitted. -
total -
extension_inputs ["
total"] -
instrument -
extension_inputs ["
instrument"] -
browserBoundPublicKey If a bbk was created, the result of getting a browser bound public key .
-
-
All other fields set as per the original step
9.10.
-
-
During "If any authenticator indicates success"; in step 2 when setting the clientExtensionResults.
Let payment_outputs be
AuthenticationExtensionsPaymentOutputswith:browserBoundSignatureA
BrowserBoundSignaturewith fields:signatureResult of generating a browser bound signature using bbk_and_algorithm and clientDataJson from create credential step 14.
Set "payment" → payment_outputs on the
[[clientExtensionsResults]].
-
-
- Client extension output
-
partial dictionary AuthenticationExtensionsClientOutputs {AuthenticationExtensionsPaymentOutputs ; };payment dictionary {AuthenticationExtensionsPaymentOutputs BrowserBoundSignature browserBoundSignature ; };dictionary {BrowserBoundSignature required ArrayBuffer signature ; };browserBoundSignaturemember, of type BrowserBoundSignature-
NoneOutputs of the browser bound signature procedure.
-
signaturemember, of type ArrayBuffer The output of the browser bound signing process.
- Authenticator extension processing
-
None
5.1.
CollectedClientPaymentData
Dictionary
dictionary CollectedClientPaymentData :CollectedClientData {required (CollectedClientAdditionalPaymentData or CollectedClientAdditionalPaymentRegistrationData )payment ; };
The
CollectedClientPaymentData
dictionary
inherits
from
CollectedClientData
.
It
contains
the
following
additional
field:
-
paymentmember, of typeCollectedClientAdditionalPaymentData(CollectedClientAdditionalPaymentData or CollectedClientAdditionalPaymentRegistrationData) -
The additional payment information to sign.
5.2.
CollectedClientAdditionalPaymentData
Dictionary
dictionary CollectedClientAdditionalPaymentData {required USVString rpId ;required USVString topOrigin ;USVString payeeName ;USVString payeeOrigin ;required PaymentCurrencyAmount total ;required PaymentCredentialInstrument instrument ;USVString browserBoundPublicKey ; };
The
CollectedClientAdditionalPaymentData
dictionary
contains
the
following
fields:
-
rpIdmember, of type USVString -
The id of the Relying Party that created the credential.
NOTE: For historical reasons, some implementations may additionally include this parameter with the name
rp. The values ofrpandrpIdmust be the same if both are present. -
topOriginmember, of type USVString -
The origin of the top level context that requested to sign the transaction details.
-
payeeNamemember, of type USVString -
The name of the payee, if present, that was displayed to the user.
-
payeeOriginmember, of type USVString -
The origin of the payee, if present, that was displayed to the user.
-
totalmember, of type PaymentCurrencyAmount -
The
PaymentCurrencyAmountof the [payment-request]totalfield. -
instrumentmember, of type PaymentCredentialInstrument -
The instrument information that was displayed to the user.
-
browserBoundPublicKeymember, of type USVString The base64url encoding of the browser bound key public key. See Base64url encoding in WebAuthn.
Note
that
there
is
no
paymentRequestOrigin
field
in
CollectedClientAdditionalPaymentData
,
because
the
origin
of
the
calling
frame
is
already
included
in
CollectedClientData
of
[webauthn-3]
.
5.3.
CollectedClientAdditionalPaymentRegistrationData
Dictionary
dictionary CollectedClientAdditionalPaymentRegistrationData {USVString browserBoundPublicKey ; };
The
CollectedClientAdditionalPaymentRegistrationData
dictionary
contains
the
following
fields:
browserBoundPublicKeymember, of type USVStringThe base64url encoding of the browser bound key public key. See Base64url encoding in WebAuthn.
6. Browser Bound Key Store
This component internal to the the user agent manages platform-dependant cryptographic key pairs including their association to SPC credentials (i.e. passkeys). This section explains the browser bound key store and procedures for creating, binding, retrieving, and signing using the browser bound key pairs.
Note: The browser bound key store needs to generate key pairs, retrieve key pairs, export public keys, and generate signatures. Many operating system provide APIs that implement these operations and provide storage of the private in a secure element on the device when available. For example Android KeyStore , Apple CryptoKit , or Windows Cryptography API: Next Generation .
The browser bound key store contains the following:
- browser_bound_map
a map from Credential ID to a key pair identifier.
- keypair_map
a map from key pair identifier to a tuple of the public private key pair and the algorithm identifier a
COSEAlgorithmIdentifier. The public private key pair is an implementation defined type.Note: The user agent may be using a cryptographic API that provides an equivalent of the keypair_map in which case the user agent would delegate this aspect to the cryptographic API.
6.1. Creating a key pair
To
create
a
key
pair
given
allowed_algorithms
a
PublicKeyCredentialParameters
returning
a
tuple
of
the
key
pair
with
its
COSEAlgorithmIdentifier
and
the
byte
array
key
pair
identifier
execute
the
following
steps:
If allowed_algorithms is an empty list, set this list to a default list containing the following in order:
type=PublicKeyCredentialTypewithalg= -7 ("ES256").type=PublicKeyCredentialTypewithalg= -257 ("RS256").
Remove any entries from allowed_algorithms that are not of type
PublicKeyCredential.Remove any entries from allowed_algorithms that the user agent does not support.
Note: User agents may support different sets of a cryptographic algorithms on different device platforms.
If allowed_algorithms ’s size
- is zero
Return null.
Note: The user agent does not add any browser bound outputs in this case.
- is greater than zero
Proceed to create the key pair:
Let chosen_algorithm be the allowed_algorithms [0].
Generate the public private key pair using the established procedure corresponding to chosen_algorithm . Refer to the IANA COSE Algorithms registry [IANA-COSE-ALGS-REG] for established key generation algorithms.
If the step above failed for any reason, return null.
Let bbk be the the key pair from the key generation step above.
Let bbk_and_algorithm be the tuple ( bbk , chosen_algorithm ).
Let bbk_id be either
A byte array intialized as follows:
Let id be an array of length 32.
Call
getRandomValues( bbk_id ).
A byte array serialization of a keypair handle from an implementation defined key generation procedure. This byte array must identify the key for later retrival when getting or creating a browser bound key .
Note: Many cryptographic APIs may return an identifier, handle, or wrapped key instead of the private key and along with the public key. For example when the private key is stored in a secure element, the private key is not directly available to the user agent, and the identifier/handle/wrapped_key must be passed into another function of the cryptographi API in order to be used.
Set keypair_map [ bbk_id ] = bbk_and_algorithm .
Return ( bbk_and_algorithm , bbk_id ).
The spec could specify to prefer algorithms in hardware storage (in given order) then algorithms in software (in the same given order). For the time being this topic may be moot since Chrome plans to support only 1 algorithm per platform in hardware. See Secure Payment Confirmation issue #288 that discusses storage type of BBKs including additional topics of which storage types should be allowed and exposing the storage type to the relying party.
6.2. Binding a key pair
To bind a key pair given the bbk_id , the byte array containing the key pair identifier, and credential_id , the byte array of the SPC credential_id (i.e. passkey id), store the identifiers in the browser_bound_map as follows:
Insert the browser bound key id into the map: browser_bound_map [ credential_id ] = bbk_id .
Return true if the map insertion succeeded.
Return false if the map insertion failed.
Note: When user agents are storing this map (such as serializing to disk) and the procedure fails, the user agent returns false here and avoids including the browser bound key in which case the relying party does not get the browser bound key on this transaction. On a subsequent payment assertion a new key pair creation will be attempted.
6.3. Retrieving a key pair
To
get
or
create
a
browser
bound
key
given
credential_id
,
a
Credential
ID
,
and
allowed_algorithms
,
a
list
of
PublicKeyCredentialParameters
,
perform
the
following
steps
that
find
an
existing
associated
key
pair
or
create
a
new
associated
key
pair
and
return
that
key
pair
with
its
algorithm.
If browser_bound_map [ credential_id ]
- exists
Retrieve the existing key pair
Let bbk_id be browser_bound_map [ credential_id ].
Let bbk_and_algorithm be keypair_map [ bbk_id ].
- Does not exist
Create and bind a new key pair
Let ( new_bbk_and_algorithm , bbk_id ) be the result of creating a key pair using allowed_algorithms .
Let binding_result be the result of binding a key pair using bbk_id and credential_id .
If binding_result is true, let bbk_and_algorithm be new_bbk_and_algorithm .
If binding_result is false, let bbk_and_algorithm be null.
Return bbk_and_algorithm .
6.4. Getting the browser bound public key
To
get
a
browser
bound
public
key
given
the
bbk_and_algorithm
,
the
tuple
of
key
pair
and
COSEAlgorithmIdentifier
returned
by
the
precedures
above:
Let bbk be bbk_and_algorithm [0].
Let algorithm be bbk_and_algorithm [1].
Retrieve the public_key of the bbk according to established procedures for the algorithm .
Let encoded_public_key be the COSE_Key encoding of public_key . Refer to credentialPublicKey from WebAuthn’s Web Authentication § 6.5.1 Attested Credential Data .
Return encoded_public_key .
6.5. Signing client data
To
generate
a
browser
bound
signature
given
the
bbk_and_algorithm
,
a
tuple
of
the
key
pair
and
COSEAlgorithmIdentifier
and
client_data_json
,
a
byte
array
containing
the
encoded
client
data,
perform
the
following
steps:
Let bbk be bbk_and_algorithm [0].
Let algorithm be bbk_and_algorithm [1].
Generate signature , a byte array, by performing the cryptographic signature algorithm on client_data_json using bbk corresponding to algorithm . Refer to the IANA COSE Algorithms registry [IANA-COSE-ALGS-REG] .
Return signature .
7. Common Data Structures
The following data structures are shared between registration and authentication.
6.1.
7.1.
PaymentCredentialInstrument
Dictionary
dictionary PaymentCredentialInstrument {; ;required USVString displayName ;required USVString icon ;boolean iconMustBeShown =true ; };
The
PaymentCredentialInstrument
dictionary
contains
the
information
to
be
displayed
to
the
user
and
signed
together
with
the
transaction
details.
It
contains
the
following
members:
-
displayNamemember, of type USVString -
The name of the payment instrument to be displayed to the user.
NOTE: See
§ 13§ 14 Internationalization Considerations for discussion about internationalization of thedisplayName. -
iconmember, of type USVString -
The URL of the icon of the payment instrument.
NOTE: The
iconURL may either identify an image on an internet-accessible server (e.g.,https://bank.com/card.png), or directly encode the icon data via a Data URL [RFC2397] . Between the two types of URLs, Data URLs offer several benefits to the Relying Party . They can improve reliability (e.g., in the case that the icon hosting server may be unavailable). They can also enhance validation because the Relying Party has cryptographic evidence of what the browser displayed to the user: the icon URL is signed as part of theCollectedClientAdditionalPaymentDatastructure.NOTE: See related accessibility considerations .
-
iconMustBeShownmember, of type boolean , defaulting totrue -
Indicates whether the specified icon must be successfully fetched and shown for the request to succeed.
7.
8.
Permissions
Policy
integration
This
specification
uses
the
"
payment
"
policy-identifier
string
from
[payment-request]
to
control
access
to
SPC
authentication,
as
per
the
PaymentRequest
constructor.
For
backwards
compatibility
with
an
earlier
version
of
this
specification,
the
Credential
Management
Credential
Type
Registry
is
extended
to
add
the
"
payment
"
policy-identifier
string
as
an
alternative
Create
Permissions
Policy
for
type
public-key
.
A
future
version
of
this
specification
may
deprecate
this
behavior
entirely.
Note:
Algorithms
specified
in
[CREDENTIAL-MANAGEMENT-1]
perform
the
actual
permissions
policy
evaluation.
This
is
because
such
policy
evaluation
needs
to
occur
when
there
is
access
to
the
current
settings
object
.
The
[[Create]](origin,
options,
sameOriginWithAncestors)
and
[[DiscoverFromExternalSource]](origin,
options,
sameOriginWithAncestors)
internal
methods
do
not
have
such
access
since
they
are
invoked
in
parallel
(by
algorithms
specified
in
[CREDENTIAL-MANAGEMENT-1]
).
8.
9.
SPC
Relying
Party
Operations
8.1.
9.1.
Verifying
an
Authentication
Assertion
In order to perform an authentication ceremony for Secure Payment Confirmation, the Relying Party MUST proceed as follows:
-
Let credential be a
PublicKeyCredentialreturned from a successful invocation of the Secure Payment Confirmation payment handler by the SPC caller .Note: As SPC is designed to enable merchant control of authentication , the entity that invokes SPC may not be the Relying Party . This first step presumes that the SPC caller has returned a credential obtained via SPC to the Relying Party .
-
Perform steps 3-21 as specified in WebAuthn , with the following changes:
-
In step 5, verify that credential .
ididentifies one of the public key credentials provided to the SPC caller by the Relying Party . -
In step 11, verify that the value of C ["
type"] is the stringpayment.get. -
In step 12, verify that the value of C ["
challenge"] equals the base64url encoding of the challenge provided to the SPC caller by the Relying Party . -
In step 13, verify that the value of C ["
origin"] matches the origin that the Relying Party expects SPC to have been called from. -
After step 13, insert the following steps:
-
Verify that the value of C ["
payment"]["rpId"] matches the Relying Party ’s origin. -
Verify that the value of C ["
payment"]["topOrigin"] matches the top-level origin that the Relying Party expects. -
Verify that the value of C ["
payment"]["payeeName"] matches the name of the payee that should have been displayed to the user, if any. -
Verify that the value of C ["
payment"]["payeeOrigin"] matches the origin of the payee that should have been displayed to the user, if any. -
Verify that the value of C ["
payment"]["total"] matches the transaction amount that should have been displayed to the user. -
Verify that the value of C ["
payment"]["instrument"] matches the payment instrument details that should have been displayed to the user.
-
-
9.
10.
User
Agent
Automation
For the purposes of user agent automation and website testing, this document defines the below [WebDriver2] extension commands . Interested parties should also consult the equivalent automation section in [webauthn-3] .
9.1.
10.1.
Set
SPC
Transaction
Mode
The Set SPC Transaction Mode WebDriver extension command instructs the user agent to place Secure Payment Confirmation into a mode where it will automatically simulate a user either accepting or rejecting the transaction confirmation UX .
The
current
transaction
automation
mode
tracks
what
automation
mode
is
currently
active
for
SPC.
It
defaults
to
"
none
".
| HTTP Method | URI Template |
|---|---|
| POST |
/session/{session
id}/secure-payment-confirmation/set-mode
|
The remote end steps are:
-
If parameters is not a JSON Object , return a WebDriver error with WebDriver error code invalid argument .
-
Let mode be the result of getting a property named
"mode"from parameters . -
If mode is undefined or is not one of "
autoAccept", "autoReject", or "autoOptOut", return a WebDriver error with WebDriver error code invalid argument . -
Set the current transaction automation mode to mode .
-
Return success with data
null.
10.
11.
Security
Considerations
As this specification builds on top of WebAuthn, the WebAuthn Security Considerations are applicable. The below subsections comprise the current Secure Payment Confirmation-specific security considerations, where this specification diverges from WebAuthn.
10.1.
11.1.
Cross-origin
authentication
ceremony
A significant departure that Secure Payment Confirmation makes from WebAuthn is in allowing a third-party to initiate an authentication ceremony using credentials for a different Relying Party , and returning the assertion to the third party. This feature can expose Relying Parties to both login and payment attacks, which are discussed here.
10.1.1.
11.1.1.
Login
Attack
As credentials created for Secure Payment Confirmation are valid WebAuthn credentials, it is possible that a Relying Party may wish to use the same credential for a given user for both login and payment. This allows a potential attack on the Relying Party’s login system, if they do not carefully verify the assertion they receive.
The attack is as follows:
-
The user visits
attacker.com, which is or pretends to be a merchant site. -
attacker.comobtains credentials for the user fromrelyingparty.com, either legitimately or by stealing them fromrelyingparty.comor another party with whomrelyingparty.comhad shared the credentials. -
attacker.cominitiates SPC authentication, and the user agrees to the transaction (which may or may not be legitimate). -
attacker.comtakes the payment assertion that they received from the API call, and sends it to the login endpoint forrelyingparty.com, e.g. by sending a POST tohttps://relyingparty.com/login. -
relyingparty.comis employing faulty assertion validation code, which checks the signature but fails to validate the necessary fields (see below), and believes the login attempt to be legitimate. -
relyingparty.comreturns e.g. a login cookie toattacker.com. The user’s account atrelyingparty.comhas now been compromised.
Relying Parties can guard against this attack in two ways.
Firstly, a Relying Party must always follow the correct assertion validation steps either for WebAuthn login or SPC payment as appropriate. In particular, the following fields can all be used to detect an inappropriate use of a credential:
-
CollectedClientData["type"]- "webauthn.get" for login, "payment.get" for SPC. -
CollectedClientData["challenge"] - this value should be provided by the Relying Party server to the site ahead of any call to either WebAuthn or SPC, and should be verified as matching an expected, appropriate, previously-provided value. -
CollectedClientData["origin"] - if SPC is being performed cross-origin, this value will contain the origin of the caller (e.g.attacker.comin the above example).
Secondly,
a
Relying
Party
can
consider
keeping
their
payment
and
login
credentials
separate.
If
doing
this,
the
Relying
Party
should
only
register
credentials
for
Secure
Payment
Confirmation
on
a
subdomain
(e.g.
https//payment.relyingparty.com
),
and
should
keep
payment
credentials
and
login
credentials
separate
in
their
database.
payment
extension
specified
to
participate
in
SPC
authentication,
and
the
specification
may
be
updated
to
reflect
that
in
the
future.
In
both
implementation
and
specification
today,
a
credential
created
with
the
payment
can
be
used
for
login,
if
the
Relying
Party
wishes.
This
is
not
expected
to
change.
10.1.2.
11.1.2.
Payment
Attack
A Secure Payment Confirmation assertion is essentially useless unless it is part of an ongoing online transaction.
A variety of mechanisms protect against an attack where a malicious third-party, instead of attempting to hijack a user account, initiates an unauthorized payment using Secure Payment Confirmation credentials (obtained either legitimately or otherwise):
-
When the attacker initiates SPC, the user will be shown UI by the User Agent that clearly states the transaction details (including the payee and amount). The user is very likely to "cancel" in this scenario.
-
If the user does agree to the transaction, and completes the subsequent WebAuthn authentication ceremony, the attacker now has a signed SPC assertion for the Relying Party .
-
If the Relying Party is not expecting a transaction, it will reject the assertion.
-
If the Relying Party is expecting a transaction, it will detect at least one of the following and reject the assertion:
-
An incorrect
CollectedClientData["challenge"], if an attacker attempts to race against a valid ongoing payment. -
An incorrect
CollectedClientData["origin"], if an attacker attempts to sit between the user and a valid merchant site and forward the assertion.
-
10.2.
11.2.
Merchant-supplied
authentication
data
The bank can and should protect against spoofing by verifying the authentication assertion they receive to ensure it aligns with the transaction details provided by the merchant.
That is because a consequence of this specification’s third-party authentication ceremony is that even in a valid transaction (i.e. one that the Relying Party is expecting), a third-party provides the transaction details that are shown to the user:
-
Transaction amount and currency
-
Payment instrument name and icon
-
Payee name and origin
This could lead to a spoofing attack, in which a merchant presents incorrect data to the user. For example, the merchant could tell the bank (in the backend) that it is initiating a purchase of $100, but then pass $1 to the SPC API (and thus show the user a $1 transaction to verify). Or the merchant could provide the correct transaction details but pass Secure Payment Confirmation credentials that don’t match what the Relying Party expects.
Secure Payment Confirmation actually makes defeating this kind of attack easier than it currently is on the web. In online payments today, the bank has to trust that the merchant showed the user the correct amount in their checkout flow (and any fraud discoveries are post-payment, when the user checks their account statement).
10.3.
11.3.
Lack
of
user
activation
requirement
If the user agent does not require user activation, as outlined in § 4.1.4 Modification of user activation requirement , some additional security mitigations should be considered. Not requiring user activation increases the risk of spam and click-jacking attacks, by allowing a Secure Payment Confirmation flow to be initiated without the user interacting with the page immediately beforehand.
In order to mitigate spam, the user agent may decide to enforce a user activation requirement after some threshold, for example after the user has already been shown a Secure Payment Confirmation flow without a user activation on the current page. In order to mitigate click-jacking attacks, the user agent may implement a time threshold in which clicks are ignored immediately after a dialog is shown.
Another
relevant
mitigation
exists
in
PaymentRequest.show()
:
the
Payment
Request
API
requires
the
document
to
be
visible,
and
thus
SPC
cannot
be
triggered
from
a
background
tab,
minimized
window,
or
other
similar
hidden
situations.
11.
12.
Privacy
Considerations
As this specification builds on top of WebAuthn, the WebAuthn Privacy Considerations are applicable. The below subsections comprise the current Secure Payment Confirmation-specific privacy considerations, where this specification diverges from WebAuthn.
11.1.
12.1.
Probing
for
credential
ids
As per WebAuthn’s section on Authentication Ceremony Privacy , implementors of Secure Payment Confirmation must make sure not to enable malicious callers (who now may not even be the Relying Party ) to distinguish between these cases:
-
A credential is not available.
-
A credential is available, but the user does not consent to use it.
If the above cases are distinguishable, information is leaked by which a malicious Relying Party could identify the user by probing for which credentials are available.
Section § 4.1.9 Steps to check if a payment can be made gives normative steps to mitigate this risk.
11.2.
12.2.
Joining
different
payment
instruments
If a Relying Party uses the same credentials for a given user across multiple payment instruments, this might allow a merchant to join information about payment instruments that might otherwise not be linked. That is, across two different transactions that a user U performs with payment instruments P1 and P2 (either on the same merchant M, or two colluding merchants M1 and M2), the merchant(s) may now be able to learn that P1 and P2 are for the same user.
For many current online payment flows this may not be a significant risk, as the user often provides sufficient information to do this joining anyway (e.g., name, email address, shipping address).
However, if payment methods that involve less identifying information (e.g., tokenization) become commonplace, it is important that ecosystem stakeholders take steps to preserve user privacy. For example:
-
Payment systems might establish rules that place limits on storage of credential ID(s) by third parties.
-
When a Relying Party assigns multiple instruments to a single SPC credential, it might choose not to share that credential ID with other parties. In this case, the Relying Party could still use the SPC credential itself (in either a first-party or third-party context) to authenticate the user.
-
A Relying Party (e.g., a bank) might enable the user to register a distinct SPC credential per payment instrument. This would not prevent the Relying Party from joining those accounts internally.
11.3.
12.3.
Credential
ID(s)
as
a
tracking
vector
Even for a single payment instrument, the credential ID(s) returned by the Relying Party could be used by a malicious entity as a tracking vector, as 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).
11.4.
12.4.
User
opt
out
The
API
option
showOptOut
tells
the
user
agent
to
provide
a
way
for
the
user
to
indicate
they
wish
to
opt
out
of
the
relying
party’s
storage
of
information.
When
the
user
invokes
this
opt
out,
an
OptOutError
is
returned
to
the
caller
to
indicate
the
user’s
intent
to
opt
out.
It
is
then
up
to
the
caller
to
act
on
the
opt
out,
e.g.
by
clearing
payment
information
stored
for
the
user.
Implementors
must
make
sure
that
the
return
of
an
OptOutError
does
not
reveal
that
the
user
has
credentials
but
did
not
complete
an
authentication.
This
can
be
mitigated
by
similar
means
as
§ 11.1
§ 12.1
Probing
for
credential
ids
,
e.g.
by
also
providing
the
user
an
opportunity
to
opt
out
on
the
interstitial
UX
in
the
case
where
a
credential
match
is
not
found.
This is not intended to be a mechanism to delete browser data or credentials - it is for the developer to prompt for opt out via the user agent. The user agent should make this clear to the user, for example with some clarifying text: "This provider may have stored information about your payment method, which you can request to be deleted."
12.
13.
Accessibility
Considerations
User
agents
render
the
icon
and
displayName
together.
Relying
parties
ensure
the
accessibility
of
the
icon
presentation
by
providing
sufficient
information
via
the
displayName
(e.g.,
if
the
icon
represents
a
bank,
by
including
the
bank
name
in
the
displayName
).
User Agents implementing this specification should follow both WebAuthn’s Accessibility Considerations and PaymentRequest’s Accessibility Considerations .
13.
14.
Internationalization
Considerations
Callers
of
the
API
should
express
the
desired
locale
of
the
transaction
dialog
as
well
as
the
localization
of
any
displayable
strings
via
the
locale
member.
In
general
this
member
should
match
the
localization
of
the
page
where
the
request
originates
(such
as
by
querying
the
lang
attribute
of
the
button
triggering
the
request).
This
specification
does
not
(yet)
include
mechanisms
for
callers
to
associate
language
or
direction
metadata
with
the
displayable
strings
they
provide
as
input
to
the
API
(e.g.,
displayName
).
In the meantime, callers of the API should:
-
Aim for consistency between values of
locale(when provided) and the language of displayable strings. -
Ensure that direction changes within a string will be correctly rendered when the string is displayed (see How to use Unicode controls for bidi text and Inline changes to base direction for more information).
Implementations (and other processes attempting to display values) should apply bidi isolation around displayable string values when inserting them into the user interface. They should set the direction when it is known, or default to first-strong ("auto") when it is not.
14.
15.
IANA
Considerations
This section adds the below-listed extension identifier to the IANA "WebAuthn Extension Identifiers" registry [IANA-WebAuthn-Registries] established by [RFC8809] .
-
WebAuthn Extension Identifier: payment
-
Description: This extension supports the following functionality defined by the Secure Payment Confirmation API: (1) it allows credential creation in a cross-origin iframe (2) it allows a party other than the Relying Party to use the credential to perform an authentication ceremony on behalf of the Relying Party, and (3) it allows the browser to identify and cache Secure Payment Confirmation credentials. For discussion of important ways in which SPC differs from Web Authentication, see in particular
§ 10§ 11 Security Considerations and§ 11§ 12 Privacy Considerations -
Specification Document: Section § 5 WebAuthn Extension - "payment" of this specification
-
Change Controller: W3C Web Payments Working Group
-
Notes: Registration follows 3 May 2023 discussion with the Web Authentication Working Group.