In-App Payments SDK

Strong Customer Authentication

Use Strong Customer Authentication to verify the buyer for 1-time charges or storing a customer card on file.

iOS
Android
In-App Payments SDK
Java (Android)

The In-App Payment SDK supports the Strong Customer Authentication (SCA) buyer verification flow for transactions where the buyer is present. When a buyer uses a payment card issued in the UK, the issuing bank may require your In-App Payments app to challenge the buyer for additional identifying information. This can happen in a 1-time charge, when a card is stored on file with Square, or when a stored card is used in a transaction.

To add the SCA flow to your app, simply follow the steps in this article to update your existing code. The In-App Payments SDK handles all of the buyer verification logic and the verification UI. You must provide the location ID, buyer contact name, and the payment ID (nonce or stored customer payment card ID) to the buyer verification method, and the SDK completes the SCA flow to return a verification token your app.

Before you start
Permalink Get a link to this section

Step 1: Add buyer verification dependencies
Permalink Get a link to this section

Add the following buyer verification dependency to your module build.gradle file

dependencies {
  def buyerVerificationVersion = '1.3.0'
  implementation "com.squareup.sdk.in-app-payments:buyer-verification:$buyerVerificationVersion"
}

Step 2: Prepare for verification flow
Permalink Get a link to this section

  1. Create a VerificationParameters object in your activity to encapsulate the information in the following list:

    • Contact. You should build the Contact object with as many contact field values as you have access to. You must provide the given name. The contact family name and city should be provided. The more complete the contact object, the lower the chance that the buyer will be challenged by the card issuing bank.

    Important

    You must provide the contact given name. The other contact information should be provided. The more complete the contact object, the lower the chance that the buyer will be challenged by the card issuing bank.

    • Payment source ID. This can be the nonce returned by the CardEntry activity or a card-on-file ID for the buyer’s payment card stored with Square.

    • Location ID. Location IDs are found in the Locations page for your application in the Developer Dashboard. The ID references a seller location and stores the physical address of the seller.

    • Buyer action. The buyer intention of storing the card on file or charging it.

Pass the VerificationParameters object into the In-App-Payments SDK verify method in Step 3.

This example creates a contact and then sets the verification parameters to the contact and a payment source ID.

  private VerificationParameters makeVerificationParameters(String paymentSourceId, BuyerAction buyerAction) {
    SquareIdentifier squareIdentifier = new SquareIdentifier.LocationToken(LOCATION_ID);
    Contact contact = new Contact.Builder()
        .familyName("Doe")
        .email("johndoe@example.com")
        .addressLines(Arrays.asList("London Eye", "Riverside Walk"))
        .city("London")
        .countryCode(Country.GB)
        .postalCode("SE1 7")
        .phone("8001234567")
        .build("John");

    return new VerificationParameters(paymentSourceId, buyerAction, squareIdentifier, contact);
  }

This steps verifies a buyer for a card to be stored or charged.

Note: A stored customer card ID can be used in place of a nonce in any of the example code that sets the 1st parameter of the VerificationParameters object.


  1. Declare a class var to store the ID of a stored card on file.

    private String paymentSourceId = "A_Customer_Card_ID";
  1. If verifying a buyer for a card to be stored, add the following code in onActivityResult:

          VerificationParameters params = makeVerificationParameters( 
              paymentSourceId, 
              new BuyerAction.Store());
          BuyerVerification.verify(
              this, params
          );

  1. If verifying a buyer in a card to be charged: Update your onActivityResult with the following code to start the buyer verification activity. The verification token is received in Step 4.

          VerificationParameters params = makeVerificationParameters(
            cardResult.getNonce(),
            new BuyerAction.Charge(new Money(100, Currency.GBP)));
          BuyerVerification.verify(
            this, params
          );

  1. Add the verification code from 2. or 3. to the onActivityResult callback in your activity.

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == DEFAULT_CARD_ENTRY_REQUEST_CODE) {
      CardEntry.handleActivityResult(data, result -> {
        if (result.isSuccess()) {
          CardDetails cardResult = result.getSuccessValue();
          Card card = cardResult.getCard();
                    
          //TODO: Add verification code from 2. or 3. (charge or store a card) here
        } else if (result.isCanceled()) {
          Toast.makeText(MainActivity.this,
              "Canceled",
              Toast.LENGTH_SHORT)
              .show();
        }
      });
    }
    if (requestCode == BuyerVerification.DEFAULT_BUYER_VERIFICATION_REQUEST_CODE) {
       //TODO: Replace with code from Step 4
    }
  }

For information about storing a customer card on file once the nonce has been verified, see Save Cards on File.

Step 4: Charge the nonce or customer card id
Permalink Get a link to this section

Note

In production, the Create Customer Card and Create Payment operations are run on your backend after your client has provided the nonce and verification token.

In this step, you charge a card for a verified buyer.

In onActivityResult for requestCode == DEFAULT_BUYER_VERIFICATION_REQUEST_CODE, send the payment source ID (nonce or stored customer payment card ID) you got in Step 3 and the verification token from this step to your back end to complete a payment with verification.

In this example, note the following:

  1. Create a helper method to print a cURL command to save a card on file.

  2. Create a helper method to print a cURL command to create a payment with the Payments API Create Payment.

Note: The cURL command is run when requestCode is DEFAULT_BUYER_VERIFICATION_REQUEST_CODE

  public void printCurlCommandSaveCard(String cardNonce) {
    String uuid = UUID.randomUUID().toString();
    Log.d("buyer_verification",
        "Run this curl command to save a card on file:\n"
        + "curl --request POST https://connect.squareup.com/v2/customers/${CUSTOMER_ID}/cards \\\n"
        + "--header \"Content-Type: application/json\" \\\n"
        + "--header \"Authorization: Bearer YOUR_ACCESS_TOKEN\" \\\n"
        + "--header \"Accept: application/json\" \\\n"
        + "--data \'{ \n"
        + "\"idempotency_key\": \"" + uuid + "\",\n"
        + "\"card_nonce\": \"" + cardNonce + "\",\n"
        + "\"billing_address\": { \n"
        + "\"address_line_1\": \"London Eye\" \n"
        + "\"address_line_2\": \"Riverside Walk\" \n"
        + "\"locality\": \"London\" \n"
        + "\"postal_code\": \"SE1 7\" \n"
        + "\"country\": \"UK\"} \n"
        + "\"cardholder_name\": \"John Doe\" \n"
        + "}\'");
}

  1. Create a helper method to print a cURL command to charge a card:

  public void printCurlCommandChargeCard(String cardNonce, String token) {
    String uuid = UUID.randomUUID().toString();
    Log.i("buyer_verification",
        "Run this curl command to charge the nonce:\n"
            + "curl --request POST https://connect.squareupsandbox.com/v2/payments \\\n"
            + "--header \"Content-Type: application/json\" \\\n"
            + "--header \"Authorization: Bearer YOUR_ACCESS_TOKEN\" \\\n"
            + "--header \"Accept: application/json\" \\\n"
            + "--data \'{\n"
            + "\"idempotency_key\": \"" + uuid + "\",\n"
            + "\"amount_money\": {\n"
            + "\"amount\": 100,\n"
            + "\"currency\": \"USD\"},\n"
            + "\"source_id\": \"" + cardNonce + "\",\n"
            + "\"token\": \"" + token + "\",\n"
            + "\"billing_address\": {\n"
            + "\"address_line_1\": \"London Eye    \",\n"
            + "\"address_line_2\": \"Riverside Walk\",\n"
            + "\"locality\": \"London\",\n"
            + "\"postal_code\": \"SE1 7\",\n"
            + "\"country\": \"UK\"} ,\n"
            + "\"cardholder_name\": \"John Doe\"\n"
            + "}\'");
  }

  1. Update onActivityResult for requestCode == DEFAULT_BUYER_VERIFICATION_REQUEST_CODE to call the cURL helper methods to store and charge a card:

  @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == DEFAULT_BUYER_VERIFICATION_REQUEST_CODE) {
      BuyerVerification.handleActivityResult(data, result -> {
        if (result.isSuccess()) {
          //Charge the card with the verification token and nonce
          printCurlCommandChargeCard(
            nonce, 
            result.getSuccessValue().getVerificationToken());
                         
          //Store the card with the nonce    
          printCurlCommandSaveCard(nonce);

        } else if (result.isError()) {
          Log.d("buyer_verification","Error on verification:" 
            + result.getErrorValue().getMessage());
        }
      });
    }
  }