Web Checkout Integration

The Samsung Pay Web Checkout feature can be easily implemented on your website.

Prerequisites

Before you can integrate Samsung Pay Web Checkout, the following requirements must be met:

  • You have a Samsung Pay merchant ID. To obtain it, complete the partner onboarding process.

  • The acquirer and issuer support tokenized transactions for in-app purchases, according to card network specifications.

Integrating Samsung Pay Web Checkout

To integrate the Samsung Pay Web Checkout solution to your website:

  1. Include the Samsung Pay Web SDK JavaScript file in your website front-end:

    <script src="https://img.mpay.samsung.com/gsmpi/sdk/samsungpay_web_sdk.js"></script>
    
  2. Define the supported payment methods and Samsung Pay API version in the paymentMethods object.
    You must also provide your unique merchant ID in the serviceId key.

    const paymentMethods = {
      "version": "2",
      "serviceId": "dcc1cbb25d6a470bb42926",
      "protocol": "PROTOCOL_3DS",
      "allowedBrands": ["visa","mastercard"]
    }
    
  3. Initialize the Samsung Pay client by creating an instance of the PaymentClient object.
    You must also define the operation environment for your Web Checkout:

    • STAGE = staging environment, used for testing
    • PRODUCTION = production environment, for actual payments
    const samsungPayClient = new SamsungPay.PaymentClient({environment: "STAGE"});
    
  4. Check whether Samsung Pay is supported for the payment request, using the isReadyToPay() method with the paymentMethods object:

    samsungPayClient.isReadyToPay(paymentMethods).then(function(response) {
      if (response.result) {
        // add a payment button 
      }
    }).catch(function(err) {
      console.error(err); 
    });
    
  5. Create a container for the Samsung Pay button:

    <div id="samsungpay-container"></div>
    
  6. Implement the Samsung Pay button.
    When the user clicks the button, the onClick() listener is triggered.

    function createAndAddButton() {
      const samsungPayButton = samsungPayClient.createButton({
        onClick: onSamsungPayButtonClicked,        
        buttonStyle: "black",
        type: "buy"
      });
    
      document.getElementById("samsungpay-container").appendChild(samsungPayButton);
    }
    
  7. Create the transaction information.
    The transactionDetail object contains the order number, merchant information, and total amount for the purchase.

    const transactionDetail = {
      "orderNumber": "DSTRF345789dsgTY",
      "merchant": {
        "name": "Virtual Shop",
        "url": "virtualshop.com",
        "id": "xn7qfnd"
      },
      "amount": {
        "option": "FORMAT_TOTAL_ESTIMATED_AMOUNT",
        "currency": "USD",
        "total": 300
      }
    }
    
  8. Launch the payment sheet.
    When the onClick() event is triggered, your event handler must call the loadPaymentSheet() method, which initiates the Web Checkout UI flow. When the user confirms the payment from their mobile device, you receive the paymentCredential object generated by the device.

  9. Extract the payment credential information from the 3DS.Data key within the paymentCredential object and process it through your payment provider.

  10. Inform the Samsung server of the payment result using the notify() method within the paymentResult object.

samsungPayClient.loadPaymentSheet(paymentMethods, transactionDetail).then(function(paymentCredential) {
  // Process payment with provider
  ...
  ...
  const paymentResult = {
    "status": "CHARGED",
    "provider": "PG Name"
  }  
  samsungPayClient.notify(paymentResult);
}).catch(error => {
  // Show error in developer console for debugging
  console.error(err);
});

Decrypting Payment Credentials

For security reasons, the payment credential data that you receive is protected by JSON Web Encryption (JWE). To decrypt the payment credentials:

  1. Generate a DER file from your private key:

    $ openssl pkcs8 -topk8 -in Merchant.key -outform DER -nocrypt -out rsapriv.der
    
  2. Decrypt the JWE encrypted data.

    • Sample implementation in Java:

      import java.io.*;
      import java.security.*;
      import java.security.spec.PKCS8EncodedKeySpec;
      import java.util.Base64;
      import javax.crypto.*;
      ...
      public static void main(String[] args) {
        String encPayload = {{encryptedPayload}};
        String privateKeyFilePath = "./rsapriv.der";
        getDecryptedData(encPayload, privateKeyFilePath);
      }
      
      public static String getDecryptedData(String encPayload, String privateKeyFilePath) {
        String delims = "[.]";
        String[] tokens = encPayload.split(delims);
      
        Decoder urlDecoder = Base64.getUrlDecoder();
        byte[] encKey = urlDecoder.decode(tokens[1]);
        byte[] iv = urlDecoder.decode(tokens[2]);
        byte[] cipherText = urlDecoder.decode(tokens[3]);
        byte[] tag = urlDecoder.decode(tokens[4]);
        byte[] plainText = new byte[cipherText.length];
      
        try {
          // Read private key file
          File privateKeyFile = new File(privateKeyFilePath);
          DataInputStream dis = new DataInputStream(new FileInputStream(privateKeyFile));
          byte[] privKeyBytes = new byte[(int) privateKeyFile.length()];
          dis.read(privKeyBytes);
          dis.close();
      
          // Set private key spec
          PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privKeyBytes);
          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
          PrivateKey privKey = keyFactory.generatePrivate(spec);
      
          Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
          decryptCipher.init(Cipher.DECRYPT_MODE, privKey);
          byte[] plainEncKey = decryptCipher.doFinal(encKey);
      
          final Cipher aes128Cipher = Cipher.getInstance("AES/GCM/NoPadding");
          final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
          final SecretKeySpec keySpec = new SecretKeySpec(plainEncKey, "AES");
          aes128Cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
      
          int offset = aes128Cipher.update(cipherText, 0, cipherText.length, plainText, 0);
          aes128Cipher.update(tag, 0, tag.length, plainText, offset);
          aes128Cipher.doFinal(plainText, offset);
        } catch (Exception e) {
        }
        return new String(plainText);
      }
      
    • Sample implementation in C#
      The following packages for C# .netCore are required:

      Install-Package ChilkatDnCore -Version 9.5.0.69 (https://www.nuget.org/packages/ChilkatDnCore/)
      Install-Package jose-jwt (https://www.nuget.org/packages/jose-jwt/)
      
      using Jose;
      using System;
      using System.Text;
      ...
      static void Main(string[] args)
      {
        String encPayload = {{encryptedPayload}};
        String privateKeyFilePath = "./rsapriv.der";
        getDecryptedData(encPayload, privateKeyFilePath);
      }
      
      static void getDecryptedData(String encPayload, String privateKeyFilePath) {
        char delims = '.';
        string[] tokens = encPayload.Split(delims);
        byte[] header = Base64Url.Decode(tokens[0]);
        string headerString = Encoding.UTF8.GetString(header);
        Console.WriteLine("headerString: " + headerString);
        byte[] encKey = Base64Url.Decode(tokens[1]);
        byte[] iv = Base64Url.Decode(tokens[2]);
        byte[] cipherText = Base64Url.Decode(tokens[3]);
        byte[] tag = Base64Url.Decode(tokens[4]);
        byte[] plainText = new byte[cipherText.Length];
      
        Chilkat.Rsa rsa = new Chilkat.Rsa();
        bool success = rsa.UnlockComponent("Anything for 30-day trial");
        if (success != true) {
          Console.WriteLine(rsa.LastErrorText);
          return;
        }
      
        Chilkat.PrivateKey privateKey = new Chilkat.PrivateKey();
        success = privateKey.LoadPemFile(privateKeyFilePath);
        if (success != true) {
          Console.WriteLine(privateKey.LastErrorText);
          return;
        }
      
        success = rsa.ImportPrivateKeyObj(privateKey);
        if (success != true) {
          Console.WriteLine(rsa.LastErrorText);
          return;
        }
      
        rsa.EncodingMode = "base64";
        rsa.OaepPadding = false;
        bool usePrivateKey = true;
        byte[] plainEncKey = rsa.DecryptBytes(encKey, usePrivateKey);
        Console.WriteLine(
            "plainEncKey: " + Encoding.UTF8.GetString(plainEncKey) + ", size: " + plainEncKey.Length);
      
        AesGcmEncryption aesGcmEngine = new AesGcmEncryption(128);
        plainText = aesGcmEngine.Decrypt(null, plainEncKey, iv, cipherText, tag);
        Console.WriteLine("plainText: " + Encoding.UTF8.GetString(plainText));
      }