Payment Form: Cookbook

Verify the Buyer When Using a Nonce for an Online Payment

Strong Customer Authentication (SCA) is required in some geographical areas and when used can reduce fraudulent payments. SCA is generally friction-free for the buyer, but a card-issuing bank might require additional authentication for some payments. In those cases, buyers must verify their identity with the bank using additional secure authentication.

Before you start Permalink Get a link to this section

  • If you are using OAuth, you need MERCHANT_PROFILE_READ permission.

The example code is taken from the Node.js project used in Walkthrough: Integrate Square Payments in a Website. At a high level, the example shows you how to:

  1. Construct a buyer verification request object.

  2. Call the verifyBuyer function.

  3. Post the verification token to your backend.

  4. Use the verification token and nonce to create a payment or store a card on file.

Step 1: Initialize SqPaymentForm with a location ID Permalink Get a link to this section

The payment form must be initialized with the location ID of the seller location. Square needs to know the seller location so it can determine whether the seller is in scope for SCA. An exception is thrown if your code calls the verifyBuyer function without initializing the payment form with a location ID.

The following example adds locationId: "REPLACE_WITH_LOCATION_ID", to the SqPaymentForm JavaScript initialization block.

Important

When testing the SCA flow in the Square Sandbox, be sure to initialize SqPaymentForm with a UK location ID.

  1. In index.html, add the new line after applicationId: "REPLACE_WITH_APPLICATION_ID",.

  2. Replace REPLACE_WITH_APPLICATION_ID and REPLACE_WITH_LOCATION_ID with your application ID and location ID. If needed, you can get these values from the Developer Dashboard.

     // Create and initialize a payment form object
     const paymentForm = new SqPaymentForm({
       // Initialize the payment form elements
       
       //TODO: Replace with your sandbox application ID
       applicationId: "REPLACE_WITH_APPLICATION_ID",
       locationId: "REPLACE_WITH_LOCATION_ID",  //ADD this line
       // ...
     });

Step 2: Declare a verification details object Permalink Get a link to this section

Declare an object that includes the intent of the payment request and an instance of SqContact. The SqContact.givenName field value is required.

If the nonce is being used to charge a card (CHARGE), the amount to charge is required. If the nonce is being used to store a card (STORE), do not include a charge amount in the verification details.

Did you know?

billingContact fields are optional, with the exception of the required givenName field. However, to reduce the chance that a buyer is challenged, the fields should be set with as much billing contact information as your application can provide.

For charging a card:

      const verificationDetails = { 
        intent: 'CHARGE', 
        amount: '1.00', 
        currencyCode: 'USD', 
        billingContact: {
          givenName: 'Jane',
          familyName: 'Doe'
        }
      };    

For saving a card on file:

      const verificationDetails = { 
        intent: 'STORE', 
        billingContact: {
          givenName: 'Jane',
          familyName: 'Doe'
        }
      };    

Step 3: Call the verifyBuyer method Permalink Get a link to this section

In the cardNonceResponseReceived callback, call verifyBuyer with the verification details declared in step 2, card nonce, and callback function to get the token.

Note

The card nonce should not be posted to your backend until the verifyBuyer callback has been invoked. The verification token and nonce are then posted together with the fetch API call.

In this step, you modify the existing cardNonceResponseReceived callback:

  1. Add the verifyBuyer function call.

  2. Move the fetch API call into the callback argument of verifyBuyer.

Did you know?

You can use a Sandbox test value to simulate a card nonce while developing your application.

    /*
     * callback function: cardNonceResponseReceived
     * Triggered when: SqPaymentForm completes a card nonce request
     */
    cardNonceResponseReceived: function (errors, nonce, cardData) {

      //Initiate SCA flow
      paymentForm.verifyBuyer(
           nonce, 
           verificationDetails, 
           function(err, verificationResult) {
            if (err == null) {
              //TODO: Move existing Fetch API call here
            }
      }); 
    }

Did you know?

To force a verification challenge in the Sandbox, set the card nonce to cnon:card-nonce-requires-verification.

Step 4: Update client-side JavaScript to post a token Permalink Get a link to this section

In this step, modify your client-side logic to send a buyer a verification token to your backend along with the nonce that you are sending.

If the buyer is verified, the verificationResult.token parameter contains a buyer verification token to be provided to your backend process that creates the charge.

The following code shows the fetch API used to post a nonce. Edit the request body, as shown in the following code block.

  fetch('process-payment', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({  //UPDATE this `body` object to use the following code
      nonce: nonce,
      idempotency_key: idempotency_key,
      location_id: paymentForm.options.locationId,
      token: verificationResult.token
    })
  })
  .catch(err => {
    alert('Network error: ' + err);
  })
  .then(response => {
    if (!response.ok) {
      return response.json().then(
        errorInfo => Promise.reject(errorInfo)); 
    }
    return response.json(); 
  })
  .then(data => {
    console.log(data); 
    alert('Payment complete successfully!\nCheck browser developer console for more details');
  })
  .catch(err => {
    console.error(err);
    alert('Payment failed to complete!\nCheck browser developer console for more details');
  });

Step 5: Create a payment Permalink Get a link to this section

Locate your server-side code that listens for the POST from the client and gets the posted values to create the payment.

Add verificationToken: requestParams.token, to the request body, as shown in the following code:

app.post('/process-payment', async (req, res) => {
  const requestParams = req.body;

  // Charge the customer's card
  const paymentsApi = client.paymentsApi;
  const requestBody = {
    sourceId: requestParams.nonce,
    amountMoney: {
      amount: 100, // $1.00 charge
      currency: 'USD'
    },
    locationId: requestParams.location_id,
    idempotencyKey: requestParams.idempotency_key,
    verificationToken: requestParams.token  // ADD this line
  };

  try {
    const response = await paymentsApi.createPayment(requestBody);
    res.status(200).json({
      'title': 'Payment Successful',
      'result': response.result
    });
  } catch(error) {
    let errorResult = null;
    if (error instanceof ApiError) {
      errorResult = error.errors;
    } else {
      errorResult = error;
    }
    res.status(500).json({
      'title': 'Payment Failure',
      'result': errorResult
    });
  }
});

To learn how to save the nonce as a card on file, see the Customers API Save cards on file example.