Register a Secure Payment Confirmation

To use Secure Payment Confirmation (SPC) in a transaction, the customer must first register an authenticator. This process is very similar to the WebAuthn registration process, with the addition of a payment extension.

In this article, issuing banks acting as relying parties (RPs) can learn how to implement SPC registration. The user experience is further explained in the overview of Secure Payment Confirmation.

How does Secure Payment Confirmation registration work?

SPC is built as an extension to the WebAuthn standard.

As of April 2022, SPC only supports User Verifying Platform Authenticators (UVPA) on desktop. This means the customer needs to be on a desktop or laptop with an embedded authenticator such as:

  • Unlock feature including Touch ID on a macOS device
  • Windows Hello on a Windows device

Register the device

The relying party's (RP's) registration of a device should follow a sufficiently strong user verification process. The RP must make sure that the customer has signed in to the website using strong authentication so that the account is not easily hijacked. Be careful: a lack of security in this process puts SPC at risk as well.

Once the RP has successfully authenticated the customer, the customer can now register a device.

Typical registration workflow on the relying party's website

Feature detection

Before asking the customer to register the device, the RP must check that the browser supports SPC.

const isSecurePaymentConfirmationSupported = async () => {
  if (!'PaymentRequest' in window) {
    return [false, 'Payment Request API is not supported'];

  try {
    // The data below is the minimum required to create the request and
    // check if a payment can be made.
    const supportedInstruments = [
        supportedMethods: "secure-payment-confirmation",
        data: {
          // RP's hostname as its ID
          rpId: 'rp.example',
          // A dummy credential ID
          credentialIds: [new Uint8Array(1)],
          // A dummy challenge
          challenge: new Uint8Array(1),
          instrument: {
            // Non-empty display name string
            displayName: ' ',
            // Transparent-black pixel.
            icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==',
          // A dummy merchant origin
          payeeOrigin: 'https://non-existent.example',

    const details = {
      // Dummy shopping details
      total: {label: 'Total', amount: {currency: 'USD', value: '0'}},

    const request = new PaymentRequest(supportedInstruments, details);
    const canMakePayment = await request.canMakePayment();
    return [canMakePayment, canMakePayment ? '' : 'SPC is not available'];
  } catch (error) {
    return [false, error.message];

isSecurePaymentConfirmationSupported().then(result => {
  const [isSecurePaymentConfirmationSupported, reason] = result;
  if (isSecurePaymentConfirmationSupported) {
    // Display the payment button that invokes SPC.
  } else {
    // Fallback to the legacy authentication method.

Register an authenticator

To register a device for SPC, follow the WebAuthn registration process with the following requirements:

  • The platform authenticator is required: authenticatorSelection.authenticatorAttachment is platform.
  • The user verification is required: authenticatorSelection.userVerification is required.
  • Discoverable credentials (resident keys) are required: authenticatorSelection.residentKey is required.

In addition, specify a "payment" extension with isPayment: true. Specifying this extension without meeting the above requirements will throw an exception

Some other caveats:

  • the hostname of the RP. The eTLD+1 part of the domain must match where it's being registered. It can be used for authentication on domains that match eTLD+1.
  • a binary expression of the user identifier. The same identifier will be returned on successful authentication so the RP should provide a consistent user identifier of the card holder.
  • excludeCredentials: an array of credentials so that the RP can avoid registering the same authenticator.

For more on the WebAuthn registration process, refer to

Example registration code:

const options = {
  challenge: new Uint8Array([21...]),
  rp: {
    id: "rp.example",
    name: "Fancy Bank",
  user: {
    id: new Uint8Array([21...]),
    name: "",
    displayName: "Jane Doe",
  excludeCredentials: [{
    id: new Uint8Array([21...]),
    type: 'public-key',
    transports: ['internal'],
  }, ...],
  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 to
  // allow credential creation in an iframe, and so that the browser knows this
  // credential relates to SPC.
  extensions: {
    "payment": {
      isPayment: true,

try {
  const credential = await navigator.credentials.create({ publicKey: options });
  // Send new credential info to server for verification and registration.
} catch (e) {
  // No acceptable authenticator or user refused consent. Handle appropriately.

After a successful registration, the RP receives a credential to send to the server for verification.

Verify registration

On the server, the RP must verify the credential and keep the public key for later use. The server-side registration process is the same as an ordinary WebAuthn registration. Nothing additional is required to comply with SPC.

Registration from within an iframe

If the payer hasn't registered their device with the RP (payment issuer), the payer can register on the merchant website. After a successful authentication during a purchase, the RP can request the payer register their device indirectly, from within an iframe.

Workflow of registration on a merchant website during payment.

To do so, the merchant or parent must explicitly allow this action within an iframe using the Permissions Policy. The issuer follows the same steps to register an authenticator within an iframe.

There are two approaches for the merchant to allow registration:

  1. The iframe tag in the HTML served from the merchant domain adds an allow attribute:

    <iframe name="iframe" allow="payment"></iframe>

    Make sure the allow attribute contains payment and the RP origin that invokes WebAuthn registration.

  2. The parent frame document (served from the merchant domain) is sent with a Permissions-Policy HTTP header:

    Permissions-Policy: payment=(self "")

Next steps

Once a device is registered to the relying party, the customer can confirm payments on the merchant's website using Secure Payment Confirmation.