forked from w3c/secure-payment-confirmation
-
Notifications
You must be signed in to change notification settings - Fork 2
/
spec.bs
770 lines (569 loc) · 32 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
<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
Level: 1
URL: https://w3c.github.io/secure-payment-confirmation
Editor: Rouslan Solomakhin, Google https://www.google.com/, rouslan@chromium.org
Editor: Stephen McGruer, Google https://www.google.com/, smcgruer@chromium.org
Abstract: This specification describes data structures, formats, algorithms, and
processing models to facilitate [[webauthn-3]] based payments on the Web.
Complain About: missing-example-ids true
Markup Shorthands: markdown yes
</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
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: payment-request; urlPrefix: https://w3c.github.io/payment-request/
type: dfn
text: payment method; url: dfn-payment-method
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-permission
text: payment request accessibility considerations; url: accessibility-considerations
spec: web-authn; urlPrefix: https://w3c.github.io/webauthn/
type: dfn
text: authentication ceremony; url: authentication-ceremony
text: relying party; url: relying-party
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
</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]], whilst relaxing certain
constraints to meet the needs of payment processing.
Similarly to [[webauthn-3]], this specification defines two related processes
involving a user. The first is [[#sctn-enrollment]], where a relationship is
created between the user and the [=Relying Party=]. The second is
[[#sctn-authentication]], where a specific payment from the user to a
recipient (possibly via an intermediary payment service provider) is
authenticated for the [=Relying Party=]. An important concept in Secure Payment
Confirmation is that with the permission of the [=Relying Party=], the
merchant or another entity may initiate an authentication ceremony on the
[=Relying Party's=] behalf.
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}
The below use case scenarios illustrate the need for a payment-specific
extension to [[webauthn-3]], rather than just asking web developers to build
their own flows on-top of [[webauthn-3]] registration and authentication.
We presume that the general use case of cryptographic-based authentication for
online transactions is well established.
Note: These sections are still a WIP.
### Verifying an authenticated payment ### {#sctn-use-case-verifying-payment}
A user is performing an online transaction based on cryptographic
authentication (i.e. either WebAuthn or this specification). The user completes
the authentication and the issuing bank now wishes to verify the signed
cryptogram that they received.
If the bank or merchant site is using WebAuthn, the payment-specific
information must be placed in the WebAuthn
{{PublicKeyCredentialRequestOptions/challenge}}. This has 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 issuing bank may come up with
their own format for how payment information should be formatted and encoded
in the challenge - which causes fragmentation and confusion.
1. Regulations may require that the user was shown the transaction amount.
The `challenge` field cannot be used to verify that, as information included
there has no behavior impact on WebAuthn.
Secure Payment Confirmation, on the other hand:
1. Uses the `challenge` field only to defeat replay attacks, as with normal
WebAuthn.
1. Provides a specified format for transaction data, which will e.g. allow
generic verification code and test suites to be developed and shared as
appropriate.
1. Guarantees that the user agent has presented the transaction information to
the user, in a way that a malicious website (or maliciously introduced
JavaScript code on a trusted website) cannot bypass.
* The transaction information is included in the {{CollectedClientData}}
dictionary, which is not influencable by JavaScript code.
NOTE: This does assume the issuing bank trusts the user agent, but that
is already required in payment flows today.
### Registration in a bank iframe ### {#sctn-use-case-iframe-registration}
* It is very common in payment flows on the web to open an iframe to a bank for
ID&V (e.g. via an SMS OTP step-up flow). This is the highest traffic
*authenticated* touchpoint that the bank has with the user, and is an ideal
point for an enrollment flow.
* It is expected that requiring out-of-flow enrollment (e.g. on a bank
website, outside of a payment flow), would lead to far lower enrollment
rates for SPC.
* See https://github.com/w3c/webauthn/issues/1336#issuecomment-554170183
### Authentication on a merchant website ### {#sctn-use-case-merchant-authentication}
* A prime concern for merchants on the web is to prevent user drop-off during
authentication. Reducing friction as much as possible is key, so instead of
opening a bank iframe (the relying party) and letting them do SPC
authentication, merchants strongly want to perform the auth themselves
*on behalf of the bank*.
* This also means the banks don't need to build their own SPC front-end flows
for authentication; the merchants (or the payment service processors who
they use) can do so.
* Of course its ultimately up to the relying party to allow this usage, so they
don't have to if they don't like it. They could use SPC in a normal
challenge flow inside their own iframe if they wanted.
## 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.
### Enrollment ### {#sctn-sample-enrollment}
This is the first-time flow, in which a new credential is created and stored by
the issuing bank.
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 with the issuing bank of the payment instrument
over a backchannel. The issuing bank requests verification of the user,
and provides a bank-owned 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 confirming, they offer the user
the ability to enroll in SPC authentication for future payments.
1. The user consents (e.g. by clicking an "Enroll" button in the bank UX), and
the bank runs the below example code in the iframe.
1. The user goes through a WebAuthn registration flow. A new credential is
created for the user and the public key is returned to the issuing bank
who stores it in their server-side database associated with the user.
1. The verification completes; the bank iframe closes and the merchant finishes
the checkout process for the user.
The sample code for enrolling the user follows:
<pre class="example" id="enrollment-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: {
// An id that the bank server can use to identify this user in future interactions.
id: Uint8Array.from(window.atob("MIIBkzCCATigAwIBAjCCAZMwggE4oAMCAQIwggGTMII="), c=>c.charCodeAt(0)),
name: "jane.doe@example.com",
displayName: "Jane Doe",
},
// This Relying Party will accept either an ES256 or RS256 credential, but
// prefers an ES256 credential.
pubKeyCredParams: [
{
type: "public-key",
alg: -7 // "ES256"
},
{
type: "public-key",
alg: -257 // "RS256"
}
],
// This Relying Party requires user verification.
authenticatorSelection: {
userVerification: "required"
},
timeout: 360000, // 6 minutes
// Indicate that this is an SPC credential. This is currently required to
// allow credential creation in an iframe, and so that the browser knows this
// credential relates to SPC.
//
// It is expected that 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 ### {#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).
Note: This may or may not be the merchant website the user was originally
on when they registered this device; it is irrelevant here.
1. The merchant communicates with the issuing bank of the payment instrument
over a backchannel. The issuing bank requests verification of the user,
but notes that it accepts SPC and provides a list of known credential
IDs for this payment instrument.
1. The merchant runs the below example code.
1. The user accepts the transaction in the SPC UX, and performs a subsequent
WebAuthn authentication ceremony. The signed cryptogram is returned to
the merchant.
1. The merchant sends the signed cryptogram to the issuing bank via the
backchannel. The issuing bank verifies the cryptogram, and knows that
the user is both valid and 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">
if (!window.PaymentRequest) { /* PaymentRequest not available; merchant should fallback to traditional flows */ }
const request = new PaymentRequest([{
supportedMethods: "secure-payment-confirmation",
data: {
// List of credential IDs obtained from the bank.
credentialIds,
// 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",
},
timeout: 360000, // 6 minutes
}], {
total: {
label: "Total",
amount: {
currency: "USD",
value: "5.00",
},
},
});
try {
const canMakePayment = await request.canMakePayment();
if (!canMakePayment) { throw new Error('Cannot make payment'); }
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>
# Dependencies # {#sctn-dependencies}
This specification relies on several other underlying specifications, listed
below and in [[#index-defined-elsewhere]].
: <dfn>WebAuthn Conditional UI</dfn>
:: Secure Payment Confirmation only shows the transaction UX if one of the
passed credentials is valid for the current device, without requiring a user
interaction. This concept is not currently part of [[webauthn-3]], but is on
the roadmap for a future enhancement.
Until this is available, user agents can consider either storing a local
cache of WebAuthn credentials created for this device, or always showing the
transaction UX even if the user may be unable to complete the
authentication.
<div class="note">TODO: Bikeshed the name.</div>
# Enrollment # {#sctn-enrollment}
To enroll a user for Secure Payment Confirmation, relying parties should call
{{CredentialsContainer/create()|navigator.credentials.create()}}, with the
{{AuthenticationExtensionsClientInputs/payment}} [=WebAuthn Extension=]
specified.
Note: We currently require an extension in order to allow credential creation
in an iframe and to allow the browser to cache SPC credentials in the
absence of [=WebAuthn Conditional UI=]. Future versions of this
specification may remove the requirement for the extension.
# 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 transaction.
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]].
## Payment Method: Secure Payment Confirmation ## {#sctn-payment-method-spc}
<div class="note">
**TODO**: This specification also needs to monkey-patch step 12 of
{{PaymentRequest/constructor|PaymentRequest's constructor}} somehow, to enforce
that when "[=secure-payment-confirmation=]" is used, exactly one method is
given.
</div>
### Payment Method Identifier ### {#sctn-payment-method-identifier}
The [=standardized payment method identifier=] for this specification is
"<dfn>secure-payment-confirmation</dfn>".
### <dfn dictionary>SecurePaymentConfirmationRequest</dfn> Dictionary ### {#sctn-securepaymentconfirmationrequest-dictionary}
<xmp class="idl">
dictionary SecurePaymentConfirmationRequest {
required BufferSource challenge;
required FrozenArray<BufferSource> credentialIds;
required PaymentCredentialInstrument instrument;
unsigned long timeout;
AuthenticationExtensionsClientInputs extensions;
};
</xmp>
The {{SecurePaymentConfirmationRequest}} dictionary contains the following
members:
<dl dfn-type="dict-member" dfn-for="SecurePaymentConfirmationRequest">
: <dfn>challenge</dfn> member
:: A random one-time challenge that the relying party generates on the server side to prevent replay attacks.
: <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 enrollment 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.
: <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-enrollment| payment extension]]; it is added automatically.
</dl>
### 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}} `request`, are:
1. If `request.credentialIds` is empty, return `false`.
1. If `request.instrument.displayName` is empty, return `false`.
1. Download the image specified in `request.instrument.icon`. If this fails, return `false`.
Note: Performing this step here mitigates a privacy leak. **TODO**:
Document + link-to privacy section.
1. Optionally, the user agent may elect to return `false`.
Note: This covers the current Chrome behavior of checking whether the
passed credentials match those on the system, and early-exit if so. This
is a potential privacy concern, and may be removed.
1. Return `true`.
### Displaying a transaction confirmation UX ### {#sctn-transaction-confirmation-ux}
<div class="note">
**TODO**: We need to determine how best this can be specified. We tend to avoid
requiring user agents to show specific UX, but in the case of SPC we do want to
ensure that the appropriate transaction details are communicated to the user
(either via browser UX or via the authenticator device itself, if it has an
output).
</div>
### 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 an
input {{SecurePaymentConfirmationRequest}} `request`, are:
1. Create a {{AuthenticationExtensionsPaymentInputs}} dictionary, |payment|, with:
1. `isPayment` set to `true`.
1. `rpOrigin` set to **TODO**.
<div class="note">**TODO**: We don't have the rp origin here; maybe this should just go in the processing steps.</div>
1. `topOrigin` set to the origin of the top-level frame.
<div class="note">**TODO**: This is part of the PaymentRequestEvent, but it's unclear how to access that in an inbuilt PaymentHandler.</div>
1. `total` set to the `total` from the PaymentRequest.
<div class="note">**TODO**: This is part of the PaymentRequestEvent, but it's unclear how to access that in an inbuilt PaymentHandler.</div>
1. `instrument` set to `request.instrument`.
1. Create a {{PublicKeyCredentialRequestOptions}}, `publicKeyOpts`, with:
1. `challenge` set to `request.challenge`.
1. `timeout` set to `request.timeout`.
1. `userVerification` set to {{UserVerificationRequirement/required}}.
1. `extensions` set to a {{AuthenticationExtensionsClientInputs}} dictionary
whose {{AuthenticationExtensionsClientInputs/payment}} member is set to |payment|,
and whose other members are set from `request.extensions`.
1. For each |id| in `request.credentialIds`:
1. Create a {{PublicKeyCredentialDescriptor}}, |descriptor|, with:
1. `type` set to {{PublicKeyCredentialType/public-key}}
1. `id` set to |id|
1. `transports` set to a sequence of length 1 whose only member is
{{AuthenticatorTransport/internal}}.
1. Push |descriptor| onto `publicKeyOpts.allowCredentials`.
1. Let |outputCredential| be the result of calling <code><a idl for="CredentialsContainer" lt="get()">navigator.credentials.get({publicKey})</a></code>.
Note: This triggers [[webauthn-3]]'s [[webauthn-3#sctn-getAssertion|Get]] behavior
1. Return |outputCredential|.
# WebAuthn Extension - "`payment`" # {#sctn-payment-extension-enrollment}
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 credentials. 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.
: Extension identifier
:: `payment`
: Operation applicability
:: [=registration extension|Registration=] and [=authentication extension|authentication=]
: Client extension input
:: <xmp class="idl">
partial dictionary AuthenticationExtensionsClientInputs {
AuthenticationExtensionsPaymentInputs payment;
};
dictionary AuthenticationExtensionsPaymentInputs {
boolean isPayment;
// Only used for authentication.
USVString rpOrigin;
USVString topOrigin;
PaymentCurrencyAmount total;
PaymentCredentialInstrument instrument;
};
</xmp>
<dl dfn-type="dict-member" dfn-for="AuthenticationExtensionsPaymentInputs">
: <dfn>isPayment</dfn> member
:: Indicates that the extension is active.
<div class="note">**TODO**: Find a better way to do this. Needed currently because other members are auth-time only.</div>
: <dfn>rpOrigin</dfn> member
:: The [=Relying Party=] origin of the credential(s) being used. Only valid at authentication time.
: <dfn>topOrigin</dfn> member
:: The origin of the top-level frame. Only valid at authentication time.
: <dfn>total</dfn> member
:: The total amount the user is paying to the payee. Only valid at authentication time.
: <dfn>instrument</dfn> member
:: The instrument details to be displayed to the user. Only valid at authentication time.
</dl>
: Client extension processing ([=registration extension|registration=])
:: Note: Reading [[webauthn-3]] literally, these steps don't work; extensions
are injected at step 12 of `[[Create]]` and cannot really modify anything.
However other extensions ignore that entirely and assume they can modify any
part of any WebAuthn algorithm!
When [[webauthn-3#sctn-createCredential|creating a new credential]]:
1. Remove the check for *sameOriginWithAncestors* in step 2.
Note: This allows for creating SPC credentials in a cross-origin
iframe, as long as the correct permission policy is set
(see [[#sctn-permissions-policy]]). We could additionally require and
consume a [=transient activation=] here, if we felt the permission policy
is not sufficient.
2. In step 13, set the {{CollectedClientData/type}} to "`payment.create`".
<div class="note">**TODO**: Can we and/or should we rely on `getClientExtensionResults()` instead?</div>
: Client extension processing ([=authentication extension|authentication=])
:: When [[webauthn-3#sctn-getAssertion|making an assertion]]:
1. 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 browser UX.
1. During {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)}}:
1. Skip step 6.1, which compares *options.rpId* to *effectiveDomain*
Note: This enables cross-domain authentication ceremonies; see [[#sctn-use-case-merchant-authentication]].
1. In step 9, instead of creating a {{CollectedClientData}}, instead create a {{CollectedClientPaymentData}} with:
1. `type` set to "`payment.get"`
1. `payment` set to a new {{CollectedClientAdditionalPaymentData}} with:
1. `rpOrigin` set to {{AuthenticationExtensionsPaymentInputs/rpOrigin}}.
1. `topOrigin` set to {{AuthenticationExtensionsPaymentInputs/topOrigin}}.
1. `total` set to {{AuthenticationExtensionsPaymentInputs/total}}.
1. `instrument` set {{AuthenticationExtensionsPaymentInputs/instrument}}.
1. All other members set as per the original step 9.
: Client extension output
:: None
: Authenticator extension processing
:: None
## <dfn dictionary>CollectedClientPaymentData</dfn> Dictionary ## {#sctn-collectedclientpaymentdata-dictionary}
<xmp class="idl">
dictionary CollectedClientPaymentData : CollectedClientData {
required CollectedClientAdditionalPaymentData payment;
};
</xmp>
The {{CollectedClientPaymentData}} dictionary inherits from
{{CollectedClientData}}. It contains the following additional field:
<dl dfn-type="dict-member" dfn-for="CollectedClientPaymentData">
: <dfn>payment</dfn> member
:: The additional payment information to sign.
</dl>
## <dfn dictionary>CollectedClientAdditionalPaymentData</dfn> Dictionary ## {#sctn-collectedclientadditionalpaymentdata-dictionary}
<xmp class="idl">
dictionary CollectedClientAdditionalPaymentData {
required USVString rp;
required USVString topOrigin;
required PaymentCurrencyAmount total;
required PaymentCredentialInstrument instrument;
};
</xmp>
The {{CollectedClientAdditionalPaymentData}} dictionary contains the following
fields:
<dl dfn-type="dict-member" dfn-for="CollectedClientAdditionalPaymentData">
: <dfn>rp</dfn> member
:: The relying party that created the credential.
: <dfn>topOrigin</dfn> member
:: The origin of the top level context that requested to sign the transaction details. Typically this would be called a merchant.
: <dfn>total</dfn> member
:: The {{PaymentCurrencyAmount}} of the [[payment-request]] `total` field.
: <dfn>instrument</dfn> member
:: The instrument information that was displayed to the user.
</dl>
Note that there is no `paymentRequestOrigin` field in
{{CollectedClientAdditionalPaymentData}}, because the origin of the calling
frame is already included in {{CollectedClientData}} of [[webauthn-3]].
# Common Data Structures # {#sctn-common-data-structures}
The following data structures are shared between enrollment and authentication.
## <dfn dictionary>PaymentCredentialInstrument</dfn> Dictionary ## {#sctn-paymentcredentialinstrument-dictionary}
<xmp class="idl">
dictionary PaymentCredentialInstrument {
required DOMString displayName;
required USVString icon;
};
</xmp>
The {{PaymentCredentialInstrument}} dictionary contains the information to be
displayed to the user and signed together with the transaction details. It
contains the following members:
<dl dfn-type="dict-member" dfn-for="PaymentCredentialInstrument">
: <dfn>displayName</dfn> member
:: The name of the payment instrument to be displayed to the user.
: <dfn>icon</dfn> member
:: The URL of the icon of the payment instrument.
</dl>
# Permissions Policy integration # {#sctn-permissions-policy}
This specification uses the "[=payment permission string|payment=]"
policy-identifier string from [[payment-request]] to control access to **both**
enrollment and authentication. This extends the
[[webauthn-3#sctn-permissions-policy|WebAuthn Permission Policy]].
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 {{PublicKeyCredential/[[Create]](origin, options, sameOriginWithAncestors)}} and {{PublicKeyCredential/[[DiscoverFromExternalSource]](origin, options, sameOriginWithAncestors)}} [=internal methods=] do not have such access since they are invoked [=in parallel=] (by algorithms specified in [[!CREDENTIAL-MANAGEMENT-1]]).
# Security Considerations # {#sctn-security-considerations}
Note: This section is still very much a draft.
Main considerations (on top of WebAuthn itself):
* A successful payment backed by Secure Payment Confirmation will always
require two things: the user to provide consent and the Relying Party
to accept the signed cryptogram. As such, even if a malicious party obtains
the credential list from the Relying Party, it is unlikely for fraud to
occur:
* First, the user must provide their consent (and verification) to the
website - with either browser and/or authenticator UX that shows the
transaction details.
* Assuming the user does consent and verify the transaction, the
Relying Party must still be expecting the payment, otherwise the
cryptogram is useless.
* The same argument is used against the concern that a third party (the
merchant) provides many of the input values for SPC authentication
(e.g. the card icon, name, etc). Whilst this may be confusing to the
user if the merchant is malicious, the cryptogram is ultimately useless
unless the Relying Party accepts it - and they are able to
cryptographically verify what was shown to the user.
* Allowing \[[Create]] in an iframe; see https://github.com/w3c/webauthn/issues/1336
from WebAuthn.
* Currently this is mostly amerliorated by the fact that we show a
payments-focused browser UX on SPC enrollment.
* If we got rid of that UX (under consideration), then we could require a
user gesture for calling it. This would be fine for the bank iframe
enrollment case.
# Privacy Considerations # {#sctn-privacy-considerations}
Note: This section is still very much a draft.
SPC primarily points to WebAuthn for its privacy model, but it does relax
that model in significant ways that should be considered.
* Probing for credential ids
* Currently SPC exits immediately (on Chrome) when no passed credential
matches the current device. This could be used to probe for whether the
current device matches an existing known credential. This does show a
very clear payments UX when a match is found (though that may be too late).
Note: The instant-exit may be removed in the future.
* Identifying user across different payment instruments.
* If the relying party uses the same credentials for a given user across
multiple payment instruments, this could expose that linkage to the
merchant (as they could track what sets of credentials they see for
each credit card they ask about on the backend).
* Credential ID(s) as a tracking vector
* The credential ID could be used as a tracking vector, but to obtain it
from the Relying Party the merchant already needs an as-strong
identifier to give to the Relying Party (e.g. the credit card number).
# Accessibility Considerations # {#sctn-accessibility-considerations}
User Agents implementing this specification should follow both
[[webauthn-3#accessibility-considerations|WebAuthn's Accessibility Considerations]]
and [=payment request accessibility considerations|PaymentRequest's Accessibility Considerations=].
</div>