-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathspec.bs
1675 lines (1301 loc) · 76.9 KB
/
spec.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class="metadata">
Title: Secure Payment Confirmation
Shortname: secure-payment-confirmation
Repository: w3c/secure-payment-confirmation
TR: https://www.w3.org/TR/secure-payment-confirmation/
ED: https://w3c.github.io/secure-payment-confirmation/
Prepare for TR: true
Inline Github Issues: true
Group: web-payments
Status: w3c/ED
Deadline: 2023-08-01
Level:
URL: https://w3c.github.io/secure-payment-confirmation/
Editor: Rouslan Solomakhin, w3cid 83784, Google https://www.google.com/, [email protected]
Editor: Stephen McGruer, w3cid 96463, Google https://www.google.com/, [email protected]
!Contributors: <a href="mailto:[email protected]">Ian Jacobs</a> (<a href="https://w3.org">W3C</a>)
!Contributors: <a href="mailto:[email protected]">Nick Burris</a> (<a href="https://www.google.com">Google</a>)
Abstract: Secure Payment Confirmation (SPC) is a Web API to support streamlined
authentication during a payment transaction. It is designed to scale authentication
across merchants, to be used within a wide range of authentication protocols, and
to produce cryptographic evidence that the user has confirmed transaction details.
Complain About: missing-example-ids true
Local Boilerplate: status yes
Markup Shorthands: markdown yes
WPT Display: closed
WPT Path Prefix: /secure-payment-confirmation/
Implementation Report: https://wpt.fyi/results/secure-payment-confirmation
</pre>
<pre class="anchors">
spec: credential-management-1; urlPrefix: https://w3c.github.io/webappsec-credential-management/
type: dfn
text: same-origin with its ancestors; url: same-origin-with-its-ancestors
text: request a credential; url: abstract-opdef-request-a-credential
spec: ECMAScript; urlPrefix: https://tc39.github.io/ecma262/#
type: dfn
url: sec-object-internal-methods-and-internal-slots
text: internal slot
text: internal method
spec: i18n-glossary; urlPrefix: https://www.w3.org/TR/i18n-glossary/
type: dfn
text: locale; url: dfn-locale
spec: payment-request; urlPrefix: https://w3c.github.io/payment-request/
type: dfn
text: payment method; url: dfn-payment-method
text: payment method additional data type; url: dfn-additional-data-type
text: payment request details; url: dfn-details
text: steps to validate payment method data; url: dfn-steps-to-validate-payment-method-data
text: steps to check if a payment can be made; url: dfn-steps-to-check-if-a-payment-can-be-made
text: steps to respond to a payment request; url: dfn-steps-to-respond-to-a-payment-request
text: payment permission string; url: dfn-payment
text: payment request accessibility considerations; url: accessibility-considerations
spec: payment-method-id; urlPrefix: https://w3c.github.io/payment-method-id/
type: dfn
text: registry of standardized payment methods; url: registry
spec: web-authn; urlPrefix: https://w3c.github.io/webauthn/
type: dfn
text: authentication ceremony; url: authentication-ceremony
text: credential ID; url: credential-id
text: discoverable credential; url: discoverable-credential
text: relying party; url: relying-party
text: relying party identifier; url: relying-party-identifier
text: public key credential; url: public-key-credential
text: WebAuthn Extension; url: webauthn-extensions
text: client extension; url: client-extension
text: registration extension; url: registration-extension
text: authentication extension; url: authentication-extension
text: extension identifier; url: extension-identifier
text: user member; url: dom-publickeycredentialcreationoptions-user
spec: webdriver; urlPrefix: https://w3c.github.io/webdriver/
type: dfn
text: extension command; url: dfn-extension-commands
text: getting a property; url: dfn-getting-properties
text: invalid argument; url: dfn-invalid-argument
text: remote end steps; url: dfn-remote-end-steps
text: success; url: dfn-success
text: undefined; url: dfn-undefined
text: WebDriver error; url: dfn-error
text: WebDriver error code; url: dfn-error-code
</pre>
<pre class="link-defaults">
spec:fetch; type:dfn; for:/; text:request;
spec:i18n-glossary; type:dfn; text:bidi isolation
spec:i18n-glossary; type:dfn; text:language priority list
spec:url; type:dfn; text:valid domain;
spec:html; type:dfn; for:environment settings object; text:origin
</pre>
<pre class="biblio">
{
"webauthn-conditional-ui": {
"title": "WebAuthn Conditional UI Proposal",
"href": "https://github.com/w3c/webauthn/issues/1545"
},
"IANA-WebAuthn-Registries": {
"title": "Registries for Web Authentication (WebAuthn)",
"href": "https://www.rfc-editor.org/rfc/rfc8809.html"
}
}
</pre>
<div class="non-normative">
# Introduction # {#sctn-intro}
*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 [[#sctn-registration]] (formerly "enrollment"),
where a relationship is created between the user and the [=Relying Party=]. The
second is [[#sctn-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 and to relax assumptions to
allow the API to be called in payment contexts.
## Use Cases ## {#sctn-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.
### Cryptographic evidence of transaction confirmation ### {#sctn-use-case-verifying-payment}
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
{{PublicKeyCredentialRequestOptions/challenge}}. This raises several issues:
1. It is a misuse of the `challenge` field (which is intended to defeat replay
attacks).
1. 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.
1. 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 `challenge` field.
These limitations motivate the following Secure Payment Confirmation behaviors:
1. The `challenge` field is only used to defeat replay attacks, as with plain
[[webauthn-3]].
1. SPC specifies a format for payment-specific information. This will enable
development of generic verification code and test suites.
1. 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
{{CollectedClientData}} dictionary, 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.
### Registration in a third-party iframe ### {#sctn-use-case-iframe-registration}
If a bank wishes to use [[webauthn-3]] as the [=Relying Party=], that
specification requires the bank to register the user in a first party context.
Registration can happen outside of a transaction while the user is visiting the
bank's site. It is also useful to be able to register the user during a
transaction, but any registration that interrupts the payment journey creates a
risk of transaction abandonment.
This limitation motivates the following Secure Payment Confirmation behavior:
1. SPC supports cross-origin registration from an iframe in a third-party
context. For instance, this registration might take place following some
other identity and verification (<abbr>ID&V</abbr>) flow (e.g., SMS OTP).
* See <a href="https://github.com/w3c/webauthn/issues/1656">discussion
on WebAuthn issue 1656</a>.
### Merchant control of authentication ### {#sctn-use-case-merchant-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.
## Sample API Usage Scenarios ## {#sctn-sample-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.
### Registration during a checkout ### {#sctn-sample-registration}
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.
1. 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).
1. 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.
1. The merchant opens an iframe to `bank.com`, with the `allow` attribute set to
"[=payment permission string|payment=]".
1. 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.
1. 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).
1. 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).
1. 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:
<pre class="example" id="registration-example" highlight="js">
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: "[email protected]",
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,
}
}
};
// 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.
});
</pre>
</div> <!-- non-normative -->
### Authentication on merchant site ### {#sctn-sample-authentication}
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.
1. 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).
1. 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).
1. The merchant runs the example code shown below.
1. 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.
1. 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 sample code for authenticating the user follows. Note that the example code
presumes access to await/async, for easier to read promise handling.
<pre class="example" id="authentication-example" highlight="js">
/* 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
locale: ["en"],
timeout: 360000, // 6 minutes
}], {
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 */
}
</pre>
# Terminology # {#sctn-terminology}
: <dfn export>SPC Credential</dfn>
:: A [=public key credential|WebAuthn credential=] that can be used for the
behaviors defined in this specification. When an SPC Credential is to be
used by a party other than the [=Relying Party=], the [=Relying Party=] must
explicitly opt in by declaring the credential for SPC at creation time.
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 [=public key credential|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.
: <dfn>Steps to silently determine if a credential is SPC-enabled</dfn>
:: 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 an [=SPC Credential=].
NOTE: See <a href="https://github.com/w3c/webauthn/issues/1667">WebAuthn
issue 1667</a>.
: <dfn>Steps to silently determine if a credential is available for the current device</dfn>
:: 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 [[webauthn-3#sctn-getAssertion|Get]]
call).
This allows the user agent to only conditionally display
[[#sctn-transaction-confirmation-ux|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 credential|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 inline]]. It is likely that both it and SPC could
be supported by the same underlying API.
# Registration # {#sctn-registration}
To register a user for Secure Payment Confirmation, relying parties should call
{{CredentialsContainer/create()|navigator.credentials.create()}}, with the
{{AuthenticationExtensionsClientInputs/payment}} [=WebAuthn Extension=]
specified.
<wpt>
enrollment.https.html
enrollment-in-iframe.sub.https.html
</wpt>
Note: In this specification we define an extension in order to allow
(1) credential creation in a cross-origin iframe (which WebAuthn
Levels 1 and 2 do not allow, but Level 3 <a
href="https://github.com/w3c/webauthn/pull/1801">is expected to
allow</a>) and (2) the browser to cache SPC credential IDs in the
absence of [[webauthn-conditional-ui|Conditional UI]]. If these
capabilities are 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
{{PublicKeyCredentialEntity/name}} and
{{PublicKeyCredentialUserEntity/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
{{PublicKeyCredentialEntity/name}} is shown more
consistently. Developers should continue to monitor
implementations.
# Authentication # {#sctn-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
[[#sctn-use-case-merchant-authentication]].
<!-- This WPT is to be removed after issue #216 is closed. -->
<wpt hidden>
authentication-requires-user-activation.https.html
</wpt>
## Payment Method: Secure Payment Confirmation ## {#sctn-payment-method-spc}
This specification defines a new [=payment handler=], the <dfn>Secure Payment
Confirmation payment handler</dfn>, 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.
### Payment Method Identifier ### {#sctn-payment-method-identifier}
The [=standardized payment method identifier=] for the [=Secure Payment
Confirmation payment handler=] is "<dfn>secure-payment-confirmation</dfn>".
### Registration in [[payment-method-id]] ### {#sctn-registration-in-payment-method-id}
Add the following to the [=registry of standardized payment methods=] in
[[payment-method-id]]:
: "[=secure-payment-confirmation=]"
:: The <a href="https://w3c.github.io/secure-payment-confirmation/">Secure Payment Confirmation</a> specification.
### Modification of Payment Request constructor ### {#sctn-modify-payment-request-constructor}
In the steps for the {{PaymentRequest/constructor|PaymentRequest object's constructor}},
add a new step after step 4.3:
4. Process payment methods: *[substeps 1-3 elided]*
4. If |seenPMIs| contains "[=secure-payment-confirmation=]" and the size
of |seenPMIs| is greater than 1, throw a {{RangeError}}.
### Modification of user activation requirement ### {#sctn-modify-user-activation-requirement}
In the steps for the {{PaymentRequest/show|PaymentRequest.show()}} method,
modify steps 2 and 3:
2. If the [=relevant global object=] of [=request=] does not have
[=transient activation=], the user agent MAY:
1. Return [=a promise rejected with=] with a {{"SecurityError"}}
{{DOMException}}.
3. 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
[[#sctn-security-user-activation-requirement]] for security considerations.
### <dfn dictionary>SecurePaymentConfirmationRequest</dfn> Dictionary ### {#sctn-securepaymentconfirmationrequest-dictionary}
<xmp class="idl">
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<USVString> locale;
boolean showOptOut;
};
</xmp>
The {{SecurePaymentConfirmationRequest}} dictionary contains the following
members:
<dl dfn-type="dict-member" dfn-for="SecurePaymentConfirmationRequest">
: <dfn>challenge</dfn> member
:: A random challenge that the relying party generates on the server side
to prevent replay attacks.
: <dfn>rpId</dfn> member
:: The [=Relying Party Identifier=] of the credentials.
: <dfn>credentialIds</dfn> member
:: The list of credential identifiers for the given instrument.
: <dfn>instrument</dfn> member
:: The description of the instrument name and icon to display during
registration and to be signed along with the transaction details.
: <dfn>timeout</dfn> member
:: 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 [[webauthn-3#sctn-createCredential|additional timeout guidance]].
: <dfn>payeeName</dfn> member
:: The display name of the payee that this SPC call is for (e.g., the
merchant). Optional, may be provided alongside or instead of
{{SecurePaymentConfirmationRequest/payeeOrigin}}.
: <dfn>payeeOrigin</dfn> member
:: The [=/origin=] of the payee that this SPC call is for (e.g., the
merchant). Optional, may be provided alongside or instead of
{{SecurePaymentConfirmationRequest/payeeName}}.
: <dfn>extensions</dfn> member
:: Any [=WebAuthn extensions=] that should be used for the passed
credential(s). The caller does not need to specify the
[[#sctn-payment-extension-registration| payment extension]]; it is added
automatically.
: <dfn>locale</dfn> member
:: 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 {{SecurePaymentConfirmationRequest/locale}} is 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 [[#sctn-i18n-considerations]] for more discussion.
: <dfn>showOptOut</dfn> member
:: Whether the user should be given a chance to opt-out during the
[[#sctn-transaction-confirmation-ux|transaction confirmation UX]].
Optional, default false.
</dl>
### Payment Method additional data type ### {#sctn-payment-method-additional-data-type}
The [=payment method additional data type=] for this payment method is
{{SecurePaymentConfirmationRequest}}.
### Checking if Secure Payment Confirmation is available ### {#sctn-secure-payment-confirmation-available-api}
A static API is added to {{PaymentRequest}} in order to provide developers a
simplified method of checking whether Secure Payment Confirmation is available.
<xmp class="idl">
partial interface PaymentRequest {
static Promise<boolean> isSecurePaymentConfirmationAvailable();
};
</xmp>
<dl dfn-type="attribute" dfn-for="PaymentRequest">
: {{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.
</dl>
This allows a developer to perform the following check when deciding whether to
initiate a SPC flow:
<pre class="example" id="available-example" highlight="js">
const spcAvailable =
PaymentRequest &&
PaymentRequest.isSecurePaymentConfirmationAvailable &&
await PaymentRequest.isSecurePaymentConfirmationAvailable();
</pre>
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.
### 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
input {{PaymentRequest}} |request| and {{SecurePaymentConfirmationRequest}} |data|, are:
<wpt>
constructor.https.html
constructor-validate-payment-method-data.https.html
</wpt>
1. If |data|["{{SecurePaymentConfirmationRequest/credentialIds}}"] is empty,
throw a {{RangeError}}.
1. For each |id| in |data|["{{SecurePaymentConfirmationRequest/credentialIds}}"]:
1. If |id| is empty, throw a {{RangeError}}.
1. If |data|["{{SecurePaymentConfirmationRequest/challenge}}"] is null or
empty, throw a {{TypeError}}.
1. If |data|["{{SecurePaymentConfirmationRequest/instrument}}"]["{{PaymentCredentialInstrument/displayName}}"]
is empty, throw a {{TypeError}}.
1. If |data|["{{SecurePaymentConfirmationRequest/instrument}}"]["{{PaymentCredentialInstrument/icon}}"]
is empty, throw a {{TypeError}}.
1. Run the URL parser on data["{{SecurePaymentConfirmationRequest/instrument}}"]
["{{PaymentCredentialInstrument/icon}}"]. If this returns failure, throw a
{{TypeError}}.
1. If |data|["{{SecurePaymentConfirmationRequest/rpId}}"] is not a
[=valid domain=], throw a {{TypeError}}.
1. If both |data|["{{SecurePaymentConfirmationRequest/payeeName}}"] and
|data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"] are omitted,
throw a {{TypeError}}.
1. If either of |data|["{{SecurePaymentConfirmationRequest/payeeName}}"] or
|data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"] is present and
empty, throw a {{TypeError}}.
1. If |data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"] is present:
1. Let |parsedURL| be the result of running the [=URL parser=] on
|data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"].
1. If |parsedURL| is failure, then throw a {{TypeError}}.
1. If |parsedURL|'s [=url/scheme=] is not "`https`", then throw a {{TypeError}}.
### Steps to check if a payment can be made ### {#sctn-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:
<wpt>
constructor.https.html
authentication-invalid-icon.https.html
authentication-icon-data-url.https.html
authentication-rejected.https.html
</wpt>
1. If |data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"] is present:
1. Let |parsedURL| be the result of running the [=URL parser=] on
|data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"].
1. Assert that |parsedURL| is not failure.
1. Assert that |parsedURL|'s [=url/scheme=] is "`https`".
NOTE: These pre-conditions were previously checked in the
[[#sctn-steps-to-validate-payment-method-data|steps to validate payment
method data]].
1. Set |data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"] to the
[=serialization of an origin|serialization of=] |parsedURL|'s [=url/origin=].
1. [=fetch an image resource|Fetch the image resource=] for the icon, passing «["{{ImageResource/src}}" →
|data|["{{SecurePaymentConfirmationRequest/instrument}}"]["{{PaymentCredentialInstrument/icon}}"]]»
for *image*. If this fails:
1. If |data|["{{SecurePaymentConfirmationRequest/instrument}}"]["{{PaymentCredentialInstrument/iconMustBeShown}}"]
is `true`, then return `false`.
1. Otherwise, set |data|["{{SecurePaymentConfirmationRequest/instrument}}"]["{{PaymentCredentialInstrument/icon}}"]
to an empty string.
Note: This lets the RP know that the specified icon was not shown, as the output
{{CollectedClientAdditionalPaymentData/instrument}} will have an empty icon
string.
Note: The image resource must be fetched whether or not any credential
matches, to defeat attempts to [[#sctn-privacy-probing-credential-ids|probe
for credential existence]].
1. For each |id| in |data|["{{SecurePaymentConfirmationRequest/credentialIds}}"]:
1. Run the [=steps to silently determine if a credential is available for
the current device=], passing in
|data|["{{SecurePaymentConfirmationRequest/rpId}}"] and |id|.
If the result is `false`, remove |id| from
|data|["{{SecurePaymentConfirmationRequest/credentialIds}}"].
1. If the |data|["{{SecurePaymentConfirmationRequest/rpId}}"] is
not the [=origin=] of the [=relevant settings object=] of |request|,
run the [=steps to silently determine if a credential is SPC-enabled=],
passing in |data|["{{SecurePaymentConfirmationRequest/rpId}}"] and |id|.
If the result is `false`, remove |id| from
|data|["{{SecurePaymentConfirmationRequest/credentialIds}}"].
1. If |data|["{{SecurePaymentConfirmationRequest/credentialIds}}"] is now empty,
return `false`. The user agent must maintain
[[#sctn-privacy-probing-credential-ids|authentication ceremony privacy]]
and not leak this lack of matching credentials to the caller, by:
1. Not allowing the caller to perform a timing attack on this outcome versus
the user declining to authenticate on the
[[#sctn-transaction-confirmation-ux|transaction confirmation UX]], e.g.,
by presenting an alternative interstitial that the user must interact
with.
1. Rejecting the {{PaymentRequest/show|show()}} promise with a
"{{NotAllowedError}}" {{DOMException}}.
1. Return `true`.
### Displaying a transaction confirmation UX ### {#sctn-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|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 {{CollectedClientAdditionalPaymentData/payeeName}} if it is present.
* The {{CollectedClientAdditionalPaymentData/payeeOrigin}} if it is present.
* The {{CollectedClientAdditionalPaymentData/total}}, that is the
{{PaymentCurrencyAmount/currency}} and {{PaymentCurrencyAmount/value}} of the
transaction.
* The {{CollectedClientAdditionalPaymentData/instrument}} details, that is the
payment instrument {{PaymentCredentialInstrument/displayName}} and
{{PaymentCredentialInstrument/icon}}. If an image resource could not be
fetched or decoded from the input {{PaymentCredentialInstrument/icon}},
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
{{PaymentCredentialInstrument/iconMustBeShown}} must be `false` here as
otherwise the [[#sctn-steps-to-check-if-a-payment-can-be-made|the steps
to check if a payment can be made]] would have failed previously.
The user agent MAY utilize the information in
{{SecurePaymentConfirmationRequest/locale}}, if any, to display a UX localized
into a language and using locale-based formatting consistent with that of the
website.
If {{SecurePaymentConfirmationRequest/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 {{SecurePaymentConfirmationRequest/rpId|given relying party}}.
If the user indicates that they wish to opt-out, then the user agent must reject
the {{PaymentRequest/show|show()}} promise with an
"{{OptOutError}}" {{DOMException}}. See [[#sctn-user-opt-out]].
<wpt>
authentication-optout.https.html
</wpt>
If the [=current transaction automation mode=] is not "`none`", the user agent
should first verify that it is in an automation context (see
[[WebDriver2#security|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.
### Steps to respond to a payment request ### {#sctn-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:
1. Let |topOrigin| be the [=top-level origin=] of the [=relevant settings object=] of |request|.
1. Let |payment| be a new a {{AuthenticationExtensionsPaymentInputs}} dictionary,
whose fields are:
: {{AuthenticationExtensionsPaymentInputs/isPayment}}
:: The boolean value `true`.
: {{AuthenticationExtensionsPaymentInputs/rpId}}
:: |data|["{{SecurePaymentConfirmationRequest/rpId}}"]
: {{AuthenticationExtensionsPaymentInputs/topOrigin}}
:: |topOrigin|
: {{AuthenticationExtensionsPaymentInputs/payeeName}}
:: |data|["{{SecurePaymentConfirmationRequest/payeeName}}"] if it is
present, otherwise omitted.
: {{AuthenticationExtensionsPaymentInputs/payeeOrigin}}
:: |data|["{{SecurePaymentConfirmationRequest/payeeOrigin}}"] if it is
present, otherwise omitted.
: {{AuthenticationExtensionsPaymentInputs/total}}
:: |request|.[=payment request details|[[details]]=]["{{PaymentDetailsInit/total}}"]
: {{AuthenticationExtensionsPaymentInputs/instrument}}
:: |data|["{{SecurePaymentConfirmationRequest/instrument}}"]
1. Let |extensions| be a new {{AuthenticationExtensionsClientInputs}} dictionary
whose {{AuthenticationExtensionsClientInputs/payment}} member is set to
|payment|, and whose other members are set from
|data|["{{SecurePaymentConfirmationRequest/extensions}}"].
1. Let |publicKeyOpts| be a new {{PublicKeyCredentialRequestOptions}}
dictionary, whose fields are:
: {{PublicKeyCredentialRequestOptions/challenge}}
:: |data|["{{SecurePaymentConfirmationRequest/challenge}}"]
: {{PublicKeyCredentialRequestOptions/timeout}}
:: |data|["{{SecurePaymentConfirmationRequest/timeout}}"]
: {{PublicKeyCredentialRequestOptions/rpId}}
:: |data|["{{SecurePaymentConfirmationRequest/rpId}}"]
: {{PublicKeyCredentialRequestOptions/userVerification}}
:: {{UserVerificationRequirement/required}}
: {{PublicKeyCredentialRequestOptions/extensions}}
:: |extensions|
Note: This algorithm hard-codes "required" as the value for {{PublicKeyCredentialRequestOptions/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").
1. For each |id| in |data|["{{SecurePaymentConfirmationRequest/credentialIds}}"]:
1. Let |descriptor| be a new {{PublicKeyCredentialDescriptor}} dictionary,
whose fields are:
: {{PublicKeyCredentialDescriptor/type}}
:: {{PublicKeyCredentialType/public-key}}
: {{PublicKeyCredentialDescriptor/id}}
:: |id|
: {{PublicKeyCredentialDescriptor/transports}}
:: A sequence of length 1 whose only member is
{{AuthenticatorTransport/internal}}.
1. [=list/Append=] |descriptor| to |publicKeyOpts|["{{PublicKeyCredentialRequestOptions/allowCredentials}}"].
1. Let |outputCredential| be the result of running the algorithm to
[=Request a Credential=], passing «["{{CredentialRequestOptions/publicKey}}"
→ |publicKeyOpts|]».
Note: Chrome's initial implementation does not pass the full `data.credentialIds` list 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 [[webauthn-3#sctn-getAssertion|Get]] behavior
1. Return |outputCredential|.
# WebAuthn Extension - "`payment`" # {#sctn-payment-extension-registration}
This [=client extension|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 relaxes the WebAuthn requirements to allow
credential creation in a cross-origin iframe, and also 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
{{CredentialsContainer/get()|navigator.credentials.get()}} with this extension
directly; for authentication the extension can only be accessed via
{{PaymentRequest}} with a "[=secure-payment-confirmation=]" payment method.
<wpt title="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.">
authentication-in-iframe.sub.https.html
</wpt>
: Extension identifier
:: `payment`
: Operation applicability
:: [=registration extension|Registration=] and [=authentication extension|authentication=]
: Client extension input
::
<xmp class="idl">
partial dictionary AuthenticationExtensionsClientInputs {
AuthenticationExtensionsPaymentInputs payment;