Start · Sprachen · JavaScript · Referenz · SecurePaymentConfirmationRequest

SecurePaymentConfirmationRequest

Schnittstelle

Beschreibt die Methodendaten für <code>PaymentRequest</code> mit <code>"secure-payment-confirmation"</code>, um Zahlungen per WebAuthn-Anmeldedaten (SPC) zu bestätigen.

seit JavaScript Chromium 95+ (Chrome, Edge); experimentell, nicht Kategorie: webapi

Signatur

dictionary SecurePaymentConfirmationRequest

Beschreibung

SecurePaymentConfirmationRequest ist ein Wörterbuch (Dictionary), keine instanziierbare Klasse. Man übergibt es im Feld data eines Eintrags in methodData an den Konstruktor new PaymentRequest(), wenn supportedMethods den Wert "secure-payment-confirmation" hat. Damit lässt sich die Payment Request API zur starken Kundenauthentifizierung (z. B. nach PSD2/3-D Secure) während eines Bezahlvorgangs nutzen.

Secure Payment Confirmation (SPC) baut auf WebAuthn auf: Der Nutzer hat zuvor bei seiner Bank bzw. beim Zahlungsdienstleister (der Relying Party) ein Passkey-/FIDO-Credential mit der Erweiterung payment registriert. Beim Bezahlen zeigt der Browser einen eigenen, vertrauenswürdigen Dialog mit Händler, Betrag und Zahlungsmittel (Name und Symbol der Karte) an. Bestätigt der Nutzer per Biometrie oder PIN, wird eine WebAuthn-Assertion erzeugt, die diese Transaktionsdaten kryptografisch signiert enthält.

Das Ergebnis erhält man über PaymentRequest.show() als PaymentResponse. Dessen Eigenschaft details ist ein PublicKeyCredential, das an den Server geschickt und dort geprüft wird (Challenge, Signatur, clientDataJSON mit Typ "payment.get" und den Transaktionsdaten).

Einsatzgebiet: Banken, Kartennetzwerke und Zahlungsdienstleister, die auch in fremden Händler-Kontexten (z. B. in einem Iframe mit allow="payment") eine reibungsarme, phishing-resistente Authentifizierung anbieten wollen.

Parameter

Name Typ Default Beschreibung
$challenge Pflicht BufferSource Zufällige, serverseitig erzeugte Challenge. Wird in die signierten Client-Daten aufgenommen und schützt vor Replay-Angriffen.
$rpId Pflicht string Relying-Party-ID (Domain), bei der die Credentials registriert wurden, z. B. "bank.example".
$credentialIds Pflicht Array<BufferSource> Liste der zulässigen Credential-IDs. Keine leere Liste; mindestens eine muss auf dem Gerät vorhanden sein.
$instrument Pflicht PaymentCredentialInstrument Anzeige des Zahlungsmittels: displayName (string), icon (URL, string) und optional iconMustBeShown (boolean, Standard true).
$payeeName string Anzeigename des Zahlungsempfängers. Mindestens payeeName oder payeeOrigin muss gesetzt sein.
$payeeOrigin string HTTPS-Origin des Zahlungsempfängers, z. B. "https://shop.example".
$timeout number Zeitlimit in Millisekunden für die Authentifizierung (Hinweis an den Browser).
$extensions AuthenticationExtensionsClientInputs Zusätzliche WebAuthn-Erweiterungen, die an die Assertion weitergereicht werden.
$locale Array<string> BCP-47-Sprachtags für die Darstellung von displayName und payeeName.
$showOptOut boolean false Zeigt im Dialog eine Opt-out-Option an, mit der der Nutzer die Löschung seiner SPC-Daten anfordern kann (führt zu OptOutError).

Rückgabewert

Typ
void
Beschreibung
Als Dictionary hat es keinen Rückgabewert. Das Ergebnis von PaymentRequest.show() ist ein Promise<PaymentResponse>, dessen details ein PublicKeyCredential enthält.

Beispiele

Zahlung per SPC bestätigen lassen

// Werte kommen in der Praxis vom Server der Bank
const toBuffer = (b64) => Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));

const confirmPayment = async ({ challengeB64, credentialIdB64 }) => {
  /** @type {SecurePaymentConfirmationRequest} */
  const spcData = {
    challenge: toBuffer(challengeB64),
    rpId: 'bank.example',
    credentialIds: [toBuffer(credentialIdB64)],
    instrument: {
      displayName: 'Visa •••• 4242',
      icon: 'https://bank.example/icons/visa.png',
    },
    payeeName: 'Beispiel-Shop GmbH',
    payeeOrigin: 'https://shop.example',
    timeout: 60000,
  };

  const request = new PaymentRequest(
    [{ supportedMethods: 'secure-payment-confirmation', data: spcData }],
    { total: { label: 'Gesamt', amount: { currency: 'EUR', value: '49.90' } } }
  );

  const response = await request.show(); // benötigt Nutzeraktivierung (Klick)
  await response.complete('success');
  return response.details; // PublicKeyCredential
};

Verfügbarkeit prüfen und Assertion an den Server senden

const payButton = document.querySelector('#pay');

payButton.addEventListener('click', async () => {
  if (!window.PaymentRequest) {
    console.log('Payment Request API nicht verfügbar – Fallback nutzen');
    return;
  }

  const request = new PaymentRequest(
    [{ supportedMethods: 'secure-payment-confirmation', data: spcData }],
    { total: { label: 'Gesamt', amount: { currency: 'EUR', value: '49.90' } } }
  );

  if (!(await request.canMakePayment())) {
    console.log('SPC nicht möglich – klassische 3-D-Secure-Challenge');
    return;
  }

  try {
    const response = await request.show();
    const cred = response.details;
    const b64 = (buf) => btoa(String.fromCharCode(...new Uint8Array(buf)));

    const res = await fetch('/api/spc/verify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        id: cred.id,
        clientDataJSON: b64(cred.response.clientDataJSON),
        authenticatorData: b64(cred.response.authenticatorData),
        signature: b64(cred.response.signature),
      }),
    });
    await response.complete(res.ok ? 'success' : 'fail');
  } catch (err) {
    // NotAllowedError: abgebrochen oder kein passendes Credential
    console.log(err.name);
  }
});
NotAllowedError // falls der Nutzer abbricht

Voraussetzung: SPC-fähiges Credential registrieren

// Einmalig bei der Bank (Relying Party) ausführen
const registerPaymentCredential = async (challenge, userId) => {
  const credential = await navigator.credentials.create({
    publicKey: {
      challenge,
      rp: { id: 'bank.example', name: 'Beispielbank' },
      user: { id: userId, name: 'max@example.com', displayName: 'Max Muster' },
      pubKeyCredParams: [{ type: 'public-key', alg: -7 }, { type: 'public-key', alg: -257 }],
      authenticatorSelection: {
        authenticatorAttachment: 'platform',
        userVerification: 'required',
        residentKey: 'required',
      },
      extensions: { payment: { isPayment: true } }, // macht es SPC-fähig
    },
  });
  console.log('Credential-ID:', credential.id);
  return credential;
};
Credential-ID: AbC123...