Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 125 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,112 @@ The goal is to improve payment confirmation experience with the help of WebAuthn

## Creating a credential

A new credential type is introduced for `navigator.credentials.create()` that stores the name and the icons of a payment instrument.
A new `SecurePaymentCredential` credential type is introduced for `navigator.credentials.create()` to bind descriptions of a payment instrument, i.e. a name and an icon, with a vanilla [PublicKeyCredential].

Proposed new spec that extends [Web Authentication]:
```webidl
[SecureContext, Exposed=Window]
interface SecurePaymentCredential : PublicKeyCredential {
};

partial dictionary CredentialCreationOptions {
SecurePaymentCredentialCreationOptions securePayment;
};

dictionary SecurePaymentCredentialCreationOptions {
required PublicKeyCredentialRpEntity rp;
required SecurePaymentCredentialInstrument instrument;
required BufferSource challenge;
required sequece<PublicKeyCredentialParameters> pubKeyCredParams;
unsigned long timeout;

// PublicKeyCredentialCreationOption attributes that are intentionall omitted:
// user: For a SecurePaymentCredential, |instrument| is analogous to |user|.
// excludeCredentials: No payment use case has been proposed for this field.
// attestation: Authenticator attestation is considered an anti-pattern for adoption so will not be supported.
// extensions: No payment use case has been proposed for this field.
};

dictionary SecurePaymentCredentialInstrument {
required DOMString instrumentId;
required DOMString displayName;
required USVString icon;
};
```

Example usage:
```javascript
const publicKeyCredentialCreationOptions = {
paymentInstrument: {
name: 'Mastercard****4444',
icons: [{
'src': 'icon.png',
'sizes': '48x48',
'type': 'image/png',
}],
const securePaymentConfirmationCredentialCreationOptions = {
instrument: {
instrumentId: "Q1J4AwSWD4Dx6q1DTo0MB21XDAV76",
displayName: 'Mastercard****4444',
icon: 'icon.png'
},
challenge,
rp,
user,
pubKeyCredParams,
authenticatorSelection,
timeout,
attestation,
};

// This returns a SecurePaymentCredential, which is a subtype of PublicKeyCredential.
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
securePayment: securePaymentCredentialCreationOptions
});
```

See the [Guide to Web Authentication](https://webauthn.guide/) for mode details about the `navigator.credentials` API.

### [Future] Register an existing PublicKeyCredential for Secure Payment Confirmation

The relying party of an existing PublicKeyCredential can bind it for use in Secure Payment Confirmation.

Proposed new spec that extends [Web Authentication]:
```webidl
partial dictionary SecurePaymentCredentialCreationOptions {
PublicKeyCredentialDescriptor existingCredential;
};

partial interface SecurePaymentCredential {
readonly attribute boolean createdCredential;
};
```

Example usage:
```javascript
const securePaymentConfirmationCredentialCreationOptions = {
instrument: {
instrumentId: "Q1J4AwSWD4Dx6q1DTo0MB21XDAV76",
displayName: 'Mastercard****4444',
icon: 'icon.png'
},
existingCredential: {
type: "public-key",
id: Uint8Array.from(credentialId, c => c.charCodeAt(0))
},
challenge,
rp,
pubKeyCredParams,
timeout
};

// Bind |instrument| to |credentialId|, or create a new credential if |credentialId| doesn't exist.
const credential = await navigator.credentials.create({
securePayment: securePaymentCredentialCreationOptions
});

// |credential.createdCredential| is true if the specified credential does not exist and a new one is created instead.
```


## Querying the credential

Only the creator of the credential can query it through the `navigator.credentials.get()` API.
The creator of the credential can query it through the `navigator.credentials.get()` API, as if it is a vanilla PublicKeyCredential.

```javascript
const publicKeyCredentialRequestOptions = {
challenge,
allowCredentials: [{
id: ['ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...'],
id: Uint8Array.from(credentialId, c => c.charCodeAt(0)),
type,
transports,
}],
Expand All @@ -58,26 +127,56 @@ const credential = await navigator.credentials.get({

Any origin may invoke the [Payment Request API](https://w3c.github.io/payment-request/) to prompt the user to verify a credential created by any other origin. The `PaymentRequest.show()` method must require a user gesture and display user interface with the amount of payment and the hostname of the top-level context where the `PaymentRequest` API was invoked.

Proposed new `secure-payment-confirmation` payment method:

```webidl
dictionary SecurePaymentConfirmationRequest {
SecurePaymentConfirmationAction action;
required DOMString instrumentId;
required BufferSource networkData;
unsigned long timeout;
required USVString fallbackUrl;
};

enum SecurePaymentConfirmationAction {
"authenticate",
};

dictionary SecurePaymentConfirmationResponse {
required SecurePaymentConfirmationMerchantData merchantData;
required BufferSource networkData;
required AuthenticatorAssertionResponse assertion;
};

dictionary SecurePaymentConfirmationMerchantData {
required USVString merchantOrigin;
required PaymentCurrencyAmount total;
};
```

Example usage:

```javascript
const publicKeyCredentialRequestOptions = {
const securePaymentConfirmationRequest = {
action: "authenticate",
instrumentId: "Q1J4AwSWD4Dx6q1DTo0MB21XDAV76",
challenge,
allowCredentials: [{
id: ['ADSUllKQmbqdGtpu4sjseh4cg2TxSvrbcHDTBsv4NSSX9...'],
type,
transports,
}],
timeout,
fallbackUrl: "https://fallback.example/url"
};

const request = new PaymentRequest(
[{supportedMethods: 'secure-payment-confirmation',
data: {
publicKey: publicKeyCredentialRequestOptions,
fallback: 'https://fallback.example/url',
},
data: securePaymentConfirmationRequest
}],
{total: {label: 'total', amount: {currency: 'USD', value: '20.00'}}});
const response = await request.show();

// Merchant validates |response.merchantData| and sends |response| to issuer for authentication.
```

If none of the credentials from `allowCredentials.id` are available, then the user agent will invoke the payment handler for the payment method specified in the `fallback` method. It is recommended that the `fallback` payment method supports just-in-time installation of a payment handler, so the user agent may install it just-in-time. This enables the payment handler to open a fallback URL in the payment handler window.
If the payment instrument specified by `instrumentId` is not available or if the user failed to authenticate, then the
user agent will open `fallbackUrl` inside the Secure Modal Window.

[PublicKeyCredential]: https://www.w3.org/TR/webauthn/#iface-pkcredential
[WebAuthentication]: https://www.w3.org/TR/webauthn/