Authenticeer met beveiligde betalingsbevestiging

Verkopers kunnen Secure Payment Confirmation (SPC) gebruiken als onderdeel van een sterk klantauthenticatieproces (SCA) voor een bepaalde creditcard of bankrekening. WebAuthn voert de authenticatie uit (vaak via biometrie). WebAuthn moet vooraf worden geregistreerd, waarover u meer kunt lezen in Een veilige betalingsbevestiging registreren .

Hoe een typische implementatie werkt

Het meest voorkomende gebruik van SPC is wanneer een klant een aankoop doet op de site van een handelaar en de creditcardmaatschappij of bank authenticatie van de betaler vereist.

Authenticatieworkflow.

Laten we de authenticatiestroom eens doorlopen:

  1. Een klant verstrekt zijn betalingsgegevens (zoals creditcardgegevens) aan de verkoper.
  2. De handelaar vraagt ​​aan de corresponderende uitgever of bank (relying party of RP) van de betalingsgegevens of de betaler een afzonderlijke authenticatie nodig heeft. Deze uitwisseling kan bijvoorbeeld plaatsvinden met EMV® 3-D Secure .
    • Als de RP wil dat de handelaar SPC gebruikt, en als de gebruiker zich eerder heeft geregistreerd, antwoordt de RP met een lijst met door de betaler geregistreerde identificatie-ID's en een uitdaging.
    • Als er geen authenticatie nodig is, kan de handelaar doorgaan met het voltooien van de transactie.
  3. Als er authenticatie nodig is, bepaalt de webwinkelier of de browser SPC ondersteunt .
    • Als de browser SPC niet ondersteunt, ga dan verder met de bestaande authenticatiestroom.
  4. De handelaar beroept zich op SPC. De browser geeft een bevestigingsvenster weer.
    • Als er geen referentie-ID's zijn doorgegeven door de RP, valt u terug op de bestaande authenticatiestroom. Na een succesvolle authenticatie kunt u overwegen om SPC-registratie te gebruiken om toekomstige authenticaties te stroomlijnen .
  5. De gebruiker bevestigt en authenticeert het bedrag en de bestemming van de betaling door het apparaat te ontgrendelen.
  6. De handelaar ontvangt een referentie van de authenticatie.
  7. De RP ontvangt de inloggegevens van de handelaar en verifieert de authenticiteit ervan.
  8. De RP stuurt de verificatieresultaten naar de handelaar.
  9. De verkoper laat de gebruiker een bericht zien om aan te geven of de betaling succesvol of mislukt is.

Functiedetectie

Om te detecteren of SPC in de browser wordt ondersteund, kunt u een nepoproep sturen naar canMakePayment() .

Kopieer en plak de volgende code om SPC te detecteren op de website van een verkoper.

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) {
    console.error(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.
  }
});

Authenticeer de gebruiker

Om de gebruiker te authenticeren, roept u de methode PaymentRequest.show() aan met parameters voor secure-payment-confirmation en WebAuthn:

Dit zijn de parameters die u moet opgeven voor de data van de betaalmethode, SecurePaymentConfirmationRequest .

Parameter Beschrijving
rpId De hostnaam van de RP-oorsprong als RP-ID.
challenge Een willekeurige uitdaging die herhalingsaanvallen voorkomt.
credentialIds Een reeks referentie-ID's. Bij de authenticatie van WebAuthn accepteert de eigenschap allowCredentials een array van PublicKeyCredentialDescriptor -objecten, maar in SPC geeft u alleen een lijst met referentie-ID's door.
payeeName (optioneel) Naam van de begunstigde.
payeeOrigin De herkomst van de begunstigde. In het bovengenoemde scenario is dit de oorsprong van de handelaar.
instrument Een tekenreeks voor displayName en een URL voor icon dat naar een afbeeldingsbron verwijst. Een optionele booleaanse waarde (standaard ingesteld op true ) voor iconMustBeShown die specificeert dat een pictogram met succes moet worden opgehaald en weergegeven om het verzoek te laten slagen.
timeout Time-out om de transactie in milliseconden te ondertekenen
extensions Extensies toegevoegd aan WebAuthn-aanroep. U hoeft de “betalingsextensie” niet zelf op te geven.

Bekijk deze voorbeeldcode:

// After confirming SPC is available on this browser via a feature detection,
// fetch the request options cross-origin from the RP server.
const options = fetchFromServer('https://rp.example/spc-auth-request');
const { credentialIds, challenge } = options;

const request = new PaymentRequest([{
  // Specify `secure-payment-confirmation` as payment method.
  supportedMethods: "secure-payment-confirmation",
  data: {
    // The RP ID
    rpId: 'rp.example',

    // List of credential IDs obtained from the RP server.
    credentialIds,

    // The challenge is also obtained from the RP server.
    challenge,

    // A display name and an icon that represent the payment instrument.
    instrument: {
      displayName: "Fancy Card ****1234",
      icon: "https://rp.example/card-art.png",
      iconMustBeShown: false
    },

    // The origin of the payee (merchant)
    payeeOrigin: "https://merchant.example",

    // The number of milliseconds to timeout.
    timeout: 360000,  // 6 minutes
  }
}], {
  // Payment details.
  total: {
    label: "Total",
    amount: {
      currency: "USD",
      value: "5.00",
    },
  },
});

try {
  const response = await request.show();

  // response.details is a PublicKeyCredential, with a clientDataJSON that
  // contains the transaction data for verification by the issuing bank.
  // Make sure to serialize the binary part of the credential before
  // transferring to the server.
  const result = fetchFromServer('https://rp.example/spc-auth-response', response.details);
  if (result.success) {
    await response.complete('success');
  } else {
    await response.complete('fail');
  }
} catch (err) {
  // SPC cannot be used; merchant should fallback to traditional flows
  console.error(err);
}

De functie .show() resulteert in een PaymentResponse object, behalve dat de details een openbare sleutelreferentie bevatten met een clientDataJSON die de transactiegegevens ( payment ) bevat voor verificatie door de RP.

De resulterende inloggegevens moeten cross-origineel worden overgedragen aan de RP en worden geverifieerd.

Hoe de RP de transactie verifieert

Het verifiëren van de transactiegegevens op de RP-server is de belangrijkste stap in het betaalproces.

Om de transactiegegevens te verifiëren, kan de RP het authenticatieverificatieproces van WebAuthn volgen. Bovendien moeten ze de payment verifiëren .

Een voorbeeldpayload van de clientDataJSON :

{
  "type":"payment.get",
  "challenge":"SAxYy64IvwWpoqpr8JV1CVLHDNLKXlxbtPv4Xg3cnoc",
  "origin":"https://spc-merchant.glitch.me",
  "crossOrigin":false,
  "payment":{
    "rp":"spc-rp.glitch.me",
    "topOrigin":"https://spc-merchant.glitch.me",
    "payeeOrigin":"https://spc-merchant.glitch.me",
    "total":{
      "value":"15.00",
      "currency":"USD"
    },
    "instrument":{
      "icon":"https://cdn.glitch.me/94838ffe-241b-4a67-a9e0-290bfe34c351%2Fbank.png?v=1639111444422",
      "displayName":"Fancy Card 825809751248"
    }
  }
}
  • De rp komt overeen met de oorsprong van de RP.
  • De topOrigin komt overeen met de oorsprong op het hoogste niveau die de RP verwacht (de oorsprong van de handelaar in het bovenstaande voorbeeld).
  • De payeeOrigin komt overeen met de herkomst van de begunstigde die aan de gebruiker had moeten worden weergegeven.
  • Het total komt overeen met het transactiebedrag dat aan de gebruiker had moeten worden weergegeven.
  • Het instrument komt overeen met de gegevens van het betaalinstrument die aan de gebruiker hadden moeten worden weergegeven.
const clientData = base64url.decode(response.clientDataJSON);
const clientDataJSON = JSON.parse(clientData);

if (!clientDataJSON.payment) {
  throw 'The credential does not contain payment payload.';
}

const payment = clientDataJSON.payment;
if (payment.rp !== expectedRPID ||
    payment.topOrigin !== expectedOrigin ||
    payment.payeeOrigin !== expectedOrigin ||
    payment.total.value !== '15.00' ||
    payment.total.currency !== 'USD') {
  throw 'Malformed payment information.';
}

Nadat aan alle verificatiecriteria is voldaan, kan de RP de handelaar vertellen dat de transactie succesvol is.

Volgende stappen