For the complete documentation index, see llms.txt. This page is also available as Markdown.

How to generate the x-signature

For every payout request, the Coda system will carry out a verification process to ensure its integrity. Coda will compare the x-signature header in the request with the signature of the request body. If the signatures do not match, our system will reject the request and return error (refer Error Handling for more details) This process is to ensure the integrity and security of our payout requests, reducing the risk of any payload being tampered. Here's how the signature is generated:

  1. The request body is condensed to remove any trailing spaces and carriage returns.

  2. The payload is then signed using the HmacSHA256 algorithm with a shared secret. It's important to note that this secret is different from the one used for JWT signing. Coda will provide this secret separately.

  3. The resulting signature is encoded in base64 format.

Signature generation sample code:

package com.coda.codapay.payout.model.authorizer;
import com.coda.codapay.payout.util.JWebToken;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SignatureVerifier {
  private static String generateSignature(String data, String secret) {
       try {
           byte[] hash = secret.getBytes(StandardCharsets.UTF_8);
           Mac sha256Hmac = Mac.getInstance("HmacSHA256");
           SecretKeySpec secretKey = new SecretKeySpec(hash, "HmacSHA256");
           sha256Hmac.init(secretKey);
           byte[] signedBytes = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
           return Base64.getEncoder().encodeToString(signedBytes);
       } catch (NoSuchAlgorithmException | InvalidKeyException ex) {           Logger.getLogger(JWebToken.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
           return null;
       }
   }
   private static String minifyRequestBody(String requestBody) {
       ObjectMapper objectMapper = new ObjectMapper();
       JsonNode jsonNode = null;
       try {
           jsonNode = objectMapper.readValue(requestBody, JsonNode.class);
       } catch (JsonProcessingException e) {
           throw new RuntimeException(e);
       }
       return jsonNode.toString();
   }
   public static void main(String[] args) {
       String secret = "Ob12@7n2tGVpK^cmrCa$"; 
       String payload = "{\n" +
               "    \"payout_method\": {\n" +
               "        \"type\": \"bank_transfer\",\n" +
               "        \"payment_method\": \"bank_transfer\",\n" +
               "        \"beneficiary\": {\n" +
               "            \"name\": \"Steve\",\n" +
               "            \"payout_method_details\": {\n" +
               "                \"account_currency\": \"EGP\",\n" +
               "                \"account_name\": \"John doe\",\n" +
               "                \"account_number\": \"1234567890\",\n" +
               "                \"iban\": \"EG829299835700000000001111111\",\n" +
               "                \"swift_code\": \"DEIBEGCX016\",\n" +
               "                \"bank_code\": \"AUB\"\n" +
               "            }\n" +
               "        }\n" +
               "    },\n" +
               "    \"amount\": {\n" +
               "        \"value\": \"11.11\",\n" +
               "        \"currency_code\": \"EGP\"\n" +
               "    },\n" +
               "    \"country_code\": \"EG\",\n" +
               "    \"purpose\": \"salaries\",\n" +
               "    \"reference\": \"reference john doe\",\n" +
               "    \"request_id\": \"request_id_12344545\",\n" +
               "    \"due_date\": \"2022-04-22\"\n" +
               "}";
       String minifiedRequestBody = minifyRequestBody(payload);
       // minified request body
       System.out.println(minifiedRequestBody);
       String signature = generateSignature(minifiedRequestBody,     secret); // generate and sign signature
       System.out.println(signature); // signature value for checksum pOsnb4LGor0_iOPsc_7ufSiQHslKkV6_iJ6c6tEpP3k
   }
}

Sample payload:

x-signature shared secret sample:

Remark: Please note that this secret key will be share by Coda

Expected generated x-signature value:

Last updated

Was this helpful?