Payment Form: Cookbook

Verify a Buyer When Using a Nonce for Online Payment

Verify the buyer for 1-time charges or storing a customer card on file in an online payment

Backend
Payment Form

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 may require additional authentication for some payments. In those cases, the buyer must verify their identiy with the bank using an additional secure dialog.

Before you start
Permalink Get a link to this section

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

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

  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 if the seller is in scope for SCA. An exception is thrown if your code calls the verifyBuyer function without initializing 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 v2 Sandbox (beta), be sure to initialize SqPaymentForm with a UK location ID.

Add this code your project after applicationId: "REPLACE_WITH_APPLICATION_ID",

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

Step 2: Declare 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 requred.

If the nonce is being used to charge a card (CHARGE), the amount to charge is required. If then 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 will be challenged, the fields should be set with as much billing contact information as your app 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 step 1 verification details, the 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. Step 3 will show you how to modify the fetch call to add the verification token to the post.

Did you know?

You can use a sandbox test value to simulate a card nonce while developing your app.

    /*
     * 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 token
Permalink Get a link to this section

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

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

The following code uses the fetch API to post a nonce. You will modify the code to add token: verificationResult.token to the request body.

      // alert(`The generated nonce is:\n${nonce}`);
      fetch('process-payment', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          nonce: nonce,
          token: verificationResult.token  //ADD this line
        })
      })
      .catch(err => {
        alert('Network error: ' + err);
      })
      .then(response => {
        if (!response.ok) {
          return response.text().then(errorInfo => Promise.reject(errorInfo));
        }
        return response.text();
      })
      .then(data => {
        console.log(JSON.stringify(data));
        alert('Payment complete successfully!\nCheck browser developer consolf form more details');
      })
      .catch(err => {
        console.error(err);
        alert('Payment failed to complete!\nCheck browser developer consolf form 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.


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

  // length of idempotency_key should be less than 45
  const idempotency_key = crypto.randomBytes(22).toString('hex');

  // Charge the customer's card
  const payments_api = new squareConnect.PaymentsApi();
  const request_body = {
    source_id: request_params.nonce,
    verification_token: request_params.token,
    amount_money: {
      amount: 100, // $1.00 charge
      currency: 'USD'
    },
    idempotency_key: idempotency_key
  };

  try {
    const response = await payments_api.createPayment(request_body);
    res.status(200).json({
      'title': 'Payment Successful',
      'result': response
    });
  } catch(error) {
    res.status(500).json({
      'title': 'Payment Failure',
      'result': error.response.text
    });
  }
});

See the Customers API Save Cards on File recipe to learn how to save the nonce as a card on file.

Next Steps

Strong customer authentication for Square Card on File