In-App Payments SDK

Strong Customer Authentication

Java (Android)

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

Overview Permalink Get a link to this section

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 United Kingdom, the issuing bank might require your In-App Payments application to challenge the buyer for additional identifying information. This can happen in a one-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 application, complete the following steps to update your existing code. In-App Payments SDK handles all the buyer verification logic and the verification UI. You provide the location ID, buyer contact name, and payment ID (the 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 application.

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 the 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 possible. 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 is challenged by the card issuing bank.

    • Payment source ID. This ID 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. The location IDs are found on 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's intention of storing the card on file or charging it.

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

This example creates a contact and 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.

A stored buyer's card ID can be used in place of a nonce in any of the example code that sets the first parameter of the VerificationParameters object.


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

        private String paymentSourceId = "A_Customer_Card_ID";
    
  2. If you are 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
              );
    
  3. If you are verifying a buyer for 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
              );
    
  4. Add the verification code from step 2 or step 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 after 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 provides 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 (the nonce or stored customer payment card ID) you got in step 3 and the verification token from this step to your backend 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());
        }
      });
    }
  }