Making an API Request

This page will help you to:

  • Prepare an API request payload and perform payload encryption
  • Generate and sign a client token (JWT)
  • Steps required to process a response

Making an API Request

For each request, prepare the following:

  1. Prepares the plain request content in (JSON structure).
  2. Encrypts the HTTP request body using Bank's Public Key.
  3. Generates Digital Signature (Bearer Token).
  4. Sends HTTP Request.
  5. Processes the response message.

The following section contains an implementation guide with examples.

Overview on API Request Journey


public static void main(String[] args) throws Exception {

        // 1. Prepare Request to HSBC API to HSBC API Services
        System.out.println("----- #Start of API Sample Code Steps# -----");
        HttpMethod httpMethod = POST; //Input ENUM. Value: POST, PUT, PATCH, GET, DELETE
        ApiSchema apiSchema = EDGE; //Input ENUM. Value: EDGE, GTRF. "EDGE" for API Version >= 3.0.0. Otherwise, for previous version, input "GTRF".
        System.out.println("-----#1. Start of loading Security Credentials-----");
        String bankPgpPublicKeyFile = "src/main/resources/security-credentials/Trade-Finance-Release-Sept-23-Prod/hsbc-public.key";  //Input bank public key file location
        String clientPgpPrivateKeyFile = "src/main/resources/security-credentials/Trade-Finance-Release-Sept-23-Prod/client-private.key";// Input client private key file location
        String clientPrivateKeyPassphrase = "1password"; //Input passPhrase of your key
        // 1.1 Preparing PGP Keys
        System.out.println("#1.1. Preparing PGP Keys...");
        // 1.1.1 Retrieves Bank PGP Public Keys
        System.out.println("#1.1.1 Retrieving Bank PGP public keys...");
        List<PGPPublicKey> bankPgpPublicKeys = getPublicKeys(bankPgpPublicKeyFile);
        System.out.println("#1.1.2 Setting one of the Bank PGP Public Keys as encryption key...");
        PGPPublicKey bankPgpPublicKey = getEncryptionKey(apiSchema, bankPgpPublicKeys);
        // 1.1.2. Retrieves Client PGP Private Keys
        System.out.println("#1.2.1 Retrieving Client PGP private keys...");
        List<PGPPrivateKey> clientPgpPrivateKeys = getPrivateKeys(clientPgpPrivateKeyFile, clientPrivateKeyPassphrase);
        System.out.println("#1.2.2 Setting one of the Client PGP Private Keys as signature key...");
        PGPPrivateKey clientPgpPrivateKey = clientPgpPrivateKeys.get(0);
        System.out.println("-----End of #1. loading Security Credentials-----\n");

        // 2. Prepare Request Payload
        System.out.println("-----Start of #2. Preparing the HTTP Request Payload...");
        // 2.1 Prepare Request JSON String
        String textToEncrypt = null;
        if (httpMethod != GET) {
            textToEncrypt = "{\"paramObjectKey001\":{\"paramKey001\": \"paramValue001\",\"paramKey002\": \"paramValue002\",...}}";
        }
        System.out.println("#2.1. Request Content JSON String: \n" + textToEncrypt);
        HashMap<String, String> payloadWrappers = new HashMap<String, String>();
        Boolean xHsbcCryptoSignature = false;
        switch (apiSchema) {
            case EDGE:
                xHsbcCryptoSignature = true;
                payloadWrappers.put("request", "encryptedRequestBase64");
                payloadWrappers.put("response", "encryptedResponseBase64");
                break;
            case GTRF:
                xHsbcCryptoSignature = false;
                payloadWrappers.put("request", null);
                payloadWrappers.put("response", null);
                break;
        }
        // 2.2 Generate Request Payload
        System.out.println("#2.2. Start of Generating Request Payload");
        String requestPayload = generateRequestPayload(httpMethod, payloadWrappers, textToEncrypt, bankPgpPublicKey, clientPgpPrivateKey, xHsbcCryptoSignature);
        System.out.println("-----End of #2. Preparing the HTTP Request Payload...\n");

        // 3. Generate Authorization Token
        System.out.println("-----Start of #3. Generating Authorization Token-----");
        String clientProfileId = "TAAS000000001"; // API Profile ID Bank Assigned to you.
        String oboProfileId = "customer001"; //Customer's ID on your platform. Input null if you are a Direct Client.
        HashMap<String, Object> additionalTokenClaims = (HashMap<String, Object>) apiSettings.get("additionalTokenClaims");        
        HashMap<String, String> authTokens = generateAuthTokens(httpMethod, apiSchema, clientProfileId, oboProfileId, additionalTokenClaims, requestPayload, bankPgpPublicKey, clientPgpPrivateKey, xHsbcCryptoSignature);
       
        System.out.println("-----End of of #3. Generating Authorization Token-----\n");

        // 4. Generate Request
        System.out.println("-----Start of #4. Executing API Request-----");
        //4.1 Generate URI Parameters if required:
        HashMap<String, String> requestUriParameters = new HashMap<String, String>() {
            {
                //put("paramKey001", "paramValue001"); //Input only if required
            }
        };
        //4.2 Generate Request Headers
        String clientHostingRegion = "SG"; // Your Platform or Business Operating Region, In ISO3166-alpha-2
        HashMap<String, String> additionalRequestHeaders = new HashMap<String, String>() {
            {
                //put("headerKey001", "headerValue001"); //Input only if required
            }
        };
        HashMap<String, String> requestHeaderJson = generateRequestHeaders(apiSchema, authorizationToken, clientHostingRegion, oboProfileId, additionalRequestHeaders);
        //4.3 Send API Request and save the response as String
        String apiEndpointUrl = "https://sandbox.corporate-api.hsbc.com/......"; //Input your target URL
        String responseMessage = doRequest(httpMethod, apiEndpointUrl, requestUriParameters, requestHeaderJson, requestPayload);
        System.out.println("-----End of #4. Executing API Request-----\n");

        //5. Process Response Message from Bank and save the output as String
        System.out.println("-----Start of #5 Start of Processing API Response-----");
        String processedMessage = processResponseMessage(payloadWrappers, responseMessage, bankPgpPublicKeys, clientPgpPrivateKeys, xHsbcCryptoSignature);
        System.out.println("-----End of #5 Start of Processing API Response-----\n");
        System.out.println("----- #End of API Sample Code Steps# -----");
    }

 

Step 1 - Specify API Request Operations and load security credentials

Specifies Http Method and API Version

Steps

  1. Specify HTTP Method for your target API Endpoint (Enum values).
  2. Specify API Version for your target API Endpoint.
    1. For API Version >= 3.0.0, Input Enum Value EDGE.
    2. For API Version < 3.0.0, Input Enum Value GTRF.

JAVA Code Example:

HttpMethod httpMethod = POST; //Input ENUM. Value: POST, PUT, PATCH, GET, DELETE
ApiSchema apiSchema = EDGE; //Input ENUM. Value: EDGE, GTRF. "EDGE" for API Version >= 3.0.0. Otherwise, for previous version, input "GTRF".
Specifies Key Path

Steps

  1. Specify String variable which points to the key path and name of PGP keys stored in your system.
  2. Specify String variable for your client private key passPhrase.

JAVA Code Example:

String bankPgpPublicKeyFile = "src/main/resources/security-credentials/Trade-Finance-Release-Sept-23-Prod/hsbc-public.key";  //Input bank public key file location
String clientPgpPrivateKeyFile = "src/main/resources/security-credentials/Trade-Finance-Release-Sept-23-Prod/client-private.key";// Input client private key file location
String clientPrivateKeyPassphrase = "1password"; //Input passPhrase of your key
Loads Bank Public Key from File

Steps

  1. Call sample java method getPublicKeys which would take the above fileName string as and input and output a list of PGPPublicKey.
  2. Declare bankPgpPublicKey via getEncryptionKey.
List<PGPPublicKey> bankPgpPublicKeys = getPublicKeys(bankPgpPublicKeyFile);
PGPPublicKey bankPgpPublicKey = getEncryptionKey(apiSchema, bankPgpPublicKeys);

JAVA Code Example for reference method using via Bouncy Castle


public static List<PGPPublicKey> getPublicKeys(String fileName) {
        System.out.println("  #a. Retrieving Keys from: " + fileName);
        List<PGPPublicKey> pgpPublicKeys = new ArrayList<PGPPublicKey>();
        try {
            InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));
            InputStream decoderStream = PGPUtil.getDecoderStream(inputStream);
            PGPPublicKeyRingCollection ringCollection = new PGPPublicKeyRingCollection(decoderStream, new JcaKeyFingerprintCalculator());
            PGPPublicKey pgpPublicKey = null;
            System.out.println("  #b. IDs of keys retrieved: ");            
            for (PGPPublicKeyRing ring : ringCollection) {
                for (Iterator<PGPPublicKey> iterator = ring.getPublicKeys(); iterator.hasNext(); ) {
                    pgpPublicKey = iterator.next();
                    System.out.println("      " + Long.toHexString(pgpPublicKey.getKeyID()).toUpperCase());
                    pgpPublicKeys.add(pgpPublicKey);
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (PGPException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pgpPublicKeys;
    }

public static PGPPublicKey getEncryptionKey(String apiSchema, List<PGPPublicKey> pgpPublicKeys) {
        PGPPublicKey pgpPublicKey = null;
        switch (apiSchema) {
            case EDGE:
                pgpPublicKey = pgpPublicKeys.get(0);
                break;
            case GTRF:
                for (Iterator<PGPPublicKey> it = pgpPublicKeys.iterator(); it.hasNext(); ) {
                    pgpPublicKey = it.next();
                    if (pgpPublicKey.isEncryptionKey() && !pgpPublicKey.isMasterKey()) {
                        break;
                    }
                }
        }
        System.out.println("  #a. ID of encryption key:\n      " + Long.toHexString(pgpPublicKey.getKeyID()).toUpperCase());
        return pgpPublicKey;
    }
Loads Client Private Key from file

Steps

  1. Call method getPrivateKeys which would take the above fileName string as and input and output a list of PGPPrivateKey.
  2. Declare clientPgpPrivateKey by using one from the List<PGPPrivateKey>.
List<PGPPrivateKey> clientPgpPrivateKeys = getPrivateKeys(clientPgpPrivateKeyFile, clientPrivateKeyPassPhrase);
PGPPrivateKey clientPgpPrivateKey = clientPgpPrivateKeys.get(0);

JAVA Code Example for reference method using via Bouncy Castle


public static List<PGPPrivateKey> getPrivateKeys(String fileName, String keyPassPhrase) {
        System.out.println("  #a. Retrieving Keys from: " + fileName);
        List<PGPPrivateKey> pgpPrivateKeys = new ArrayList<PGPPrivateKey>();
        try {
            InputStream inputStream = new BufferedInputStream(new FileInputStream(fileName));
            InputStream decoderStream = PGPUtil.getDecoderStream(inputStream);
            PGPSecretKeyRingCollection ringCollection = new PGPSecretKeyRingCollection(decoderStream, new JcaKeyFingerprintCalculator());
            PGPSecretKey pgpSecretKey = null;
            for (PGPSecretKeyRing ring : ringCollection) {
                for (Iterator<PGPSecretKey> iterator = ring.getSecretKeys(); iterator.hasNext(); ) {
                    pgpSecretKey = iterator.next();
                    System.out.println("  #b. IDs of keys retrieved: ");     
                    pgpPrivateKey = pgpSecretKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().build(keyPassPhrase.toCharArray()));
                    System.out.println("      " + Long.toHexString(pgpPrivateKey.getKeyID()).toUpperCase());
                    pgpPrivateKeys.add(pgpPrivateKey);
                }
            }
            return pgpPrivateKeys;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (PGPException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return pgpPrivateKeys;
    }

Step 2 - Preparing Request Payload

Prepare Request JSON String

Steps

JSONObject requestJson = new JSONObject() {
    {
        put("data",new JSONObject(){
            {
                put("paramKey001","paramValue001");
                put("paramKey002","paramValue002");
            }
        });
    }
};
String textToEncrypt = null;
if (httpMethod != GET) {
    textToEncrypt = requestJson.toString();
    //textToEncrypt = "{\"data\":{\"paramKey001\": \"paramValue001\",\"paramKey002\": \"paramValue002\",...}}";
}
Encrypts and Generates HTTP Request Payload

Steps :

  1. Convert the textToEncrypt (JSON String prepared in Step 1) to ByteArrayInputSteam
  2. Encrypt the above stream using bank public key.
    1. Optionally, compress the above encrypted data and sign it with client's private key.
  3. Base64 Encodes the above encrypted data.
  4. Wrap the Base64 Strings into JSON Format.
String textToEncrypt = null;
if (httpMethod != GET) {
    textToEncrypt = requestJson.toString();
    //textToEncrypt = "{\"data\":{\"paramKey001\": \"paramValue001\",\"paramKey002\": \"paramValue002\",...}}";
}
System.out.println("#2.1. Request Content JSON String: \n" + textToEncrypt);
HashMap payloadWrappers = new HashMap();
Boolean xHsbcCryptoSignature = false;
switch (apiSchema) {
    case EDGE:
        xHsbcCryptoSignature = true;
        payloadWrappers.put("request", "encryptedRequestBase64");
        payloadWrappers.put("response", "encryptedResponseBase64");
        break;
    case GTRF:
        xHsbcCryptoSignature = false;
        payloadWrappers.put("request", null);
        payloadWrappers.put("response", null);
        break;
}
// 2.2 Generate Request Payload
System.out.println("#2.2. Start of Generating Request Payload");
String requestPayload = generateRequestPayload(httpMethod, payloadWrappers, textToEncrypt, bankPgpPublicKey, clientPgpPrivateKey, xHsbcCryptoSignature);
System.out.println("-----End of #2. Preparing the HTTP Request Payload...\n");,>,>

JAVA Code Example for reference method

public static String generateRequestPayload(HttpMethod httpMethod, HashMap<String, String> payloadWrappers, String textToEncrypt, PGPPublicKey bankPgpPublicKey, PGPPrivateKey clientPgpPrivateKey, Boolean xHsbcCryptoSignature) {
        String requestPayload = null;
        switch (httpMethod) {
            case GET:
                requestPayload = "";
                break;
            case POST:
                String bankPgpKeyId = Long.toHexString(bankPgpPublicKey.getKeyID()).toUpperCase();
                String base64EncryptedString = encrypt(textToEncrypt, bankPgpPublicKey, clientPgpPrivateKey, xHsbcCryptoSignature);
                System.out.println("  #a. Request Payload: ");
                String payloadWrapper = payloadWrappers.get("request");
                if (payloadWrapper == null) {
                    System.out.println("  #a.1. API Schema: GTRF - Encrypted Base64 String WITHOUT payload wrapper, used for APIs versions < 3.0.0\n  #c.2. Encryption Scheme: Bank public key encrypted WITHOUT Client Private Key Signed\n  #c.3 Encryption Key Id (Bank PGP Public Key): "  + bankPgpKeyId);
                    requestPayload = base64EncryptedString;
                } else {
                    System.out.println("  #a.1. API Schema: EDGE - Encrypted Base64 String WITH payload wrapper, it is used for API version >=3");
                    JSONObject requestPayloadJson = new JSONObject();
                    try {
                        if (xHsbcCryptoSignature == true) {
                            String clientPgpKeyId = Long.toHexString(clientPgpPrivateKey.getKeyID()).toUpperCase();
                            System.out.println("  #a.2. Encryption Scheme: Bank public key encrypted WITHOUT Client Private Key Signed\n  #a.3.1 Encryption Key Id (Bank PGP Public Key): "  + bankPgpKeyId + "\n  #a.3.2 Signing Key Id (Client PGP Private Key): " + clientPgpKeyId);
                        } else {
                            System.out.println("  #a.2. Encryption Scheme: Bank public key encrypted WITHOUT Client Private Key Signature\n  #a.3 Encryption Key Id (Bank PGP Public Key): "  + bankPgpKeyId);
                        }
                        requestPayloadJson.put(payloadWrapper, base64EncryptedString);
                        requestPayload = requestPayloadJson.toString();
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
        }

        System.out.println("  #a.4 Request Payload String: \n" + requestPayload + "\n");
        return requestPayload;
    }
public static String encrypt(String textToEncrypt, PGPPublicKey bankPublicKey, PGPPrivateKey clientPrivateKey, boolean isVerifySignature) {
        if (StringUtils.isBlank(textToEncrypt)) {
            return "";
        }
        ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();
        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(textToEncrypt.getBytes());
            OutputStream out = new ArmoredOutputStream(actualOutput);
            PGPEncryptedDataGenerator encGen =
                    new PGPEncryptedDataGenerator(
                            new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256).setWithIntegrityPacket(true).setSecureRandom(
                                    new SecureRandom())
                                    .setProvider(new BouncyCastleProvider()));
            encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(bankPublicKey).setProvider(new BouncyCastleProvider()));
            OutputStream encryptedOut = encGen.open(out, new byte[inputStream.available()]);
            PGPLiteralDataGenerator lGen = new PGPLiteralDataGenerator();

            if (isVerifySignature == true) {
                PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
                OutputStream compressedData = comData.open(encryptedOut);
                PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(
                        clientPrivateKey.getPublicKeyPacket().getAlgorithm(), PGPUtil.SHA512).setProvider(new BouncyCastleProvider()));
                sGen.init(PGPSignature.BINARY_DOCUMENT, clientPrivateKey);
                Iterator<String> it = bankPublicKey.getUserIDs();
                if (it.hasNext()) {
                    PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
                    spGen.setSignerUserID(false, it.next());
                    sGen.setHashedSubpackets(spGen.generate());
                }
                sGen.generateOnePassVersion(false).encode(compressedData); // bOut
                OutputStream lOut = lGen.open(compressedData, PGPLiteralData.BINARY, "Sample-Data", new Date(),
                        new byte[inputStream.available()]); //bOut
                byte[] data = IOUtils.toByteArray(inputStream);
                lOut.write(data);
                sGen.update(data);

                lOut.close();
                lGen.close();
                sGen.generate().encode(compressedData);
                comData.close();
                compressedData.close();

            } else {
                OutputStream lOut = lGen.open(encryptedOut, PGPLiteralData.BINARY, "Sample-Data", new Date(),
                        new byte[inputStream.available()]); //bOut
                byte[] data = IOUtils.toByteArray(inputStream);
                lOut.write(data);
                lOut.close();
                lGen.close();
            }

            encryptedOut.close();
            encGen.close();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (PGPException e) {
            e.printStackTrace();
        }
        return Base64.toBase64String(actualOutput.toByteArray());
    }

Step 3 - Generate and Sign the Authentication Token

Authentication Token components

The bearer token HSBC processes to authenticate your request is in Json Web Token (JWT) Format.

The below table defines the fields to be provided in the JWT, all fields are mandatory.

Code Name Description In Http Header Example
typ Token Type Type of Token - Always set as "JWT" JWT header
  1. Authorization
  2. X-HSBC-Trade-Finance-Token
“JWT”
kid Key Id Key ID of Client PGP Key which will be used to sign this token JWT header "900864F8C11EB743"
alg Signing Algorithm Algorithm Used to Sign this token JWT header "PS256"
ver Version Always set as 1.0 JWT header "1.0"
jti JWT ID Unique ID to represent each API request's token. The format is UUID JWT payload "74760410-f963-11e8-b2a3-1bb26e1e5b69"
iat Issue At Timestamp this toekn JWT payload 1565150776
sub Subject Who is sending this request. It will always be the Client Profile ID HSBC assigned to your platform. JWT payload Client/ PARTNER Profile ID
aud Audience Who is receiving this request. It's a static value. JWT payload "baas"
obo:sub On behalf of / subject This field is used to identify End Customer on your platform for this particular request. Required only if you are a partner of HSBC. JWT payload “obo” : { “sub” : "CUSTOMER001" }
payload_hash Payload hash value Hash Value of the HTTP Request Payload. This is used by bank to verify your HTTP Request Payload are not tempered. JWT payload Authorization (HTTP Method = "POST" Only) "1dab559f1f4bf4f3ca..."
payload_hash_alg Payload hash algorithm Algorithm Used to perform Payload Hashing JWT payload "RSASHA256"
tradeAccounts Trade Accounts Trade Account Number JWT payload

X-HSBC-Trade-Finance-Token

Required only for the for the following APIs:

  1. Bank Guarantee
  2. Buyer Loans
  3. Seller Loans
  4. TradePay
  5. Import Letters of Credit
  6. Import Colection
  7. Export Letters of Credit
  8. Export Collection
"LS0tLS1CRUdJTi...."
Generating Token

Steps to prepare the Token:

  1. Generate Hashmap for JWT header according to fields specified above.
    1. Specify the signing algorithm of this token.
  2. Generate Hashmap for JWT claims according to fields specified above.
    1. Specify payloadHashAlgorithm and generate the payloadHash with requestPayload as input .
  3. Convert Your (Client) PGP Private Key to RSA.
  4. Use JwtBuilder to generate the token.

String oboProfileId = "customer001"; //Customer's ID on your platform. Input null if you are a Direct Client.
String token = generateAuthToken(httpMethod, apiSchema, clientProfileId, oboProfileId, requestPayload, clientPgpPrivateKey);

Code example of reference method

	public static HashMap<String, String> generateAuthTokens(String httpMethod, String apiSchema, String clientProfileId, String onBehalfOf, HashMap<String, Object> additionalTokenClaims, String requestPayload, PGPPublicKey bankPgpPublicKey, PGPPrivateKey clientPgpPrivateKey, boolean xHsbcCryptoSignature) {

        try {
            System.out.println("  #a. Using HashMap to build token structure...");
            HashMap<String, String> token = new HashMap<String, String>();
            // header
            HashMap<String, Object> headers = new HashMap<String, Object>();
            headers.put("kid", Long.toHexString(clientPgpPrivateKey.getKeyID()).toUpperCase());
            headers.put("typ", "JWT");
            headers.put("ver", "1.0");
            headers.put("alg", TOKEN_ALG);

            // claims
            PrivateKey clientRsaPrivateKey = new JcaPGPKeyConverter().getPrivateKey(clientPgpPrivateKey);
            HashMap<String, Object> claims = new HashMap<String, Object>();
            claims.put("jti", UUID.randomUUID().toString());
            claims.put("iat", System.currentTimeMillis() / 1000);
            claims.put("sub", clientProfileId); //API Profile ID Bank Assigned to you during on-boarding
            if (apiSchema == (ApiSchema.Edge.SCHEMA_NAME)) {
                claims.put("aud", "baas");
                // Obo, optional, only used when an API request is send on behalf of an End Customer
                if (onBehalfOf != null) {
                    HashMap<String, Object> obo = new HashMap<String, Object>();
                    obo.put("sub", onBehalfOf); //End Customer ID, provided by your platform during on-boarding
                    claims.put("obo", obo);
                }
            } else if (apiSchema == (ApiSchema.Gtrf.SCHEMA_NAME)) {
                claims.put("aud", "GTRF.MKT");
            }
            //if (requestPayload != null) {
            if (httpMethod != HttpGet.METHOD_NAME) {
                String payloadHash = DatatypeConverter.printHexBinary(MessageDigest.getInstance(TOKEN_PAYLOAD_HASH_ALG).digest(requestPayload.getBytes()))
                        .toLowerCase();
                claims.put("payload_hash", payloadHash);
                claims.put("payload_hash_alg", clientRsaPrivateKey.getAlgorithm() + TOKEN_PAYLOAD_HASH_ALG.replace("-", ""));
            }
            // print token object
            printAuthToken(headers, claims);
            System.out.println("  #b. Building JWT and Signed by: " + clientRsaPrivateKey.toString());
            JwtBuilder authorizationBuilder = Jwts.builder().setHeader(headers).setClaims(claims).signWith(clientRsaPrivateKey, SIGNATURE_ALG);
            //System.out.println("  #b. Building JWT and Signed by: " + Base64.getEncoder().encodeToString(pem.getEncoded()));
            //JwtBuilder jwtBuilder = Jwts.builder().setHeader(headers).setClaims(claims).signWith(pem, SIGNATURE_ALG);
            String authorization = authorizationBuilder.compact();
            System.out.println("  #c. Generated Authorization Token:\nJWS " + authorization);

            if (apiSchema == (ApiSchema.Edge.SCHEMA_NAME)) {
                HashMap<String, Object> xHsbcTradeFinanceClaims = new HashMap<String, Object>() {
                    {
                        put("jti", claims.get("jti"));
                        put("iat", claims.get("iat"));
                        put("sub", claims.get("sub"));
                        put("aud", claims.get("aud"));
                        if (claims.containsKey("obo")) {
                            put("obo", claims.get("obo"));
                        }
                    }
                };

                for (Map.Entry<String, Object> entry : additionalTokenClaims.entrySet()) {
                    if (entry.getKey() == "claimsNoEncrypt") {
                        Map<String, Object> xHsbcTradeFinanceClaimsNoEncrypt = (Map<String, Object>) entry.getValue();
                        for (Map.Entry<String, Object> innerEntry : xHsbcTradeFinanceClaimsNoEncrypt.entrySet()) {
                            xHsbcTradeFinanceClaims.put(innerEntry.getKey(), innerEntry.getValue());
                        }
                    }
                    if (entry.getKey() == "claimsToEncrypt") {
                        Map<String, Object> xHsbcTradeFinanceClaimsToEncrypt = (Map<String, Object>) entry.getValue();
                        for (Map.Entry<String, Object> innerEntry : xHsbcTradeFinanceClaimsToEncrypt.entrySet()) {
                            xHsbcTradeFinanceClaims.put(innerEntry.getKey(), encrypt(innerEntry.getValue().toString(), bankPgpPublicKey, clientPgpPrivateKey, xHsbcCryptoSignature));
                        }
                    }
                }
                printAuthToken(headers, xHsbcTradeFinanceClaims);
                JwtBuilder xHsbcTradeFinanceBuilder = Jwts.builder().setHeader(headers).setClaims(xHsbcTradeFinanceClaims).signWith(clientRsaPrivateKey, SIGNATURE_ALG);
                String xHsbcTradeFinance = xHsbcTradeFinanceBuilder.compact();
                System.out.println("  #c. Generated X-HSBC-Trade-Finance-Token:\nJWS " + xHsbcTradeFinance);
                token.put("xHsbcTradeFinance", xHsbcTradeFinance);
            }
            token.put("authorization", authorization);

            return token;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (PGPException e) {
            e.printStackTrace();
        }

        return null;
    }
public static void printAuthToken(Map<String, Object> header, Map<String, Object> claims) {
        System.out.println("  #a.1. Token Headers:");
        for (Map.Entry<String, Object> entry : header.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();
        System.out.println("  #a.2. Token Claims:");
        for (Map.Entry<String, Object> entry : claims.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();
    }

Step 4 - Sending HTTP Request

Generates Request Headers

Steps:

  1. Optionally, declare a Hashmap and put additional request headers.
  2. Declare a Hashmap to generate complete request headers via generateRequestHeaders

public static final HashMap<String, String> additionalRequestHeaders = new HashMap<String, String>() {
        {
            put("additionalRequestHeaderKey001", "additionalRequestHeaderValue001");
            put("additionalRequestHeaderKey002", "additionalRequestHeaderValue002");
            ...
        }
};
HashMap<⁢String, String> requestHeaders = generateRequestHeaders(apiSchema, token, clientHostingRegion, oboProfileId, additionalRequestHeaders);

JAVA Code Example for reference method

public static HashMap<String, String> generateRequestHeaders(String apiSchema, String token, String clientHostingRegion, String oboProfileId, HashMap<String, String> additionalRequestHeaders) {
        String contentType;
        HashMap⁢String, String> requestHeaders = new HashMap⁢String, String>();
        if (clientHostingRegion == "CN") {
            contentType = "text-plain";
        } else {
            contentType = "application/json";
        }
        switch (apiSchema) {
            case ("EDGE"):
                requestHeaders.put("Authorization", "JWS ".concat(token.get("authorization").toString()));
                requestHeaders.put("X-HSBC-Trade-Finance-Token", "JWS ".concat(token.get("xHsbcTradeFinance").toString()));
                requestHeaders.put("X-HSBC-countryCode", clientHostingRegion);
                requestHeaders.put("Content-Type", contentType);
                requestHeaders.put("X-HSBC-Request-Correlation-Id", String.valueOf(UUID.randomUUID()));
                if (httpMethod != HttpGet.METHOD_NAME) {
                    requestHeaders.put("X-HSBC-Request-Idempotency-Key", requestId);
       }
	            requestHeaders.put("X-HSBC-Crypto-Signature", Boolean.toString(xHsbcCryptoSignature));
                requestHeaders.putAll(additionalRequestHeaders);
                break;
            case ("GTRF"):
                requestHeaders.put("Authorization", "JWS ".concat(token));
                requestHeaders.put("CountryCode", clientHostingRegion);
                requestHeaders.put("Content-Type", contentType);
                requestHeaders.put("requestId", String.valueOf(UUID.randomUUID()).replace("-", ""));
                requestHeaders.put("requestTime", ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                requestHeaders.put("schemaVersion", "1.0.0");
                requestHeaders.putAll(additionalRequestHeaders);
                break;
        }
		printHttpRequestHeaders(requestHeaders);  //print request headers
        return requestHeaders;
    }
public static void printHttpRequestHeaders(HashMap headers) {
        for (HashMap.Entry entry : headers.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
        System.out.println();
    },>,>
Sends HTTP Request

Steps:

  1. Declares a String httpMethod for your corresponding HTTP Request Operations.
    1. Values can be "POST", "PUT", "PATCH", "GET", "DELETE".
  2. Declares a String for the corresponding API endpoint URL.
  3. Declares a Hashmap requestUriParameters and put request URI Parameters if any.
    1. Otherwise, declare an empty Hashmap.
  4. Declare a String responseMessage to save the output string from doRequest method.
String httpMethod = "POST",
String apiEndpointUrl = "https://%API_ENDPOINT_URL%;
HashMap <String, String> requestUriParameters = HashMap <String, String>() {
	{
		put("requestUriParameterKey001", "requestUriParameterValue001");
		put("requestUriParameterKey002", "requestUriParameterValue002");
		...
	}
}
String responseMessage = doRequest(httpMethod, apiEndpointUrl, requestUriParameters, requestHeaders, requestPayload);

JAVA Code Example for reference method using org.apache.http

public static String doRequest(String httpMethod, String apiEndpointUrl, HashMap<String, String> requestUriParameters, HashMap<String, String> requestHeaderJson, String requestPayload) {
        System.out.println("-----#Preparing API Request#-----");
        String textToDecrypt = null;
        HttpHost proxyHost = null;
        RequestConfig config = null;
        HttpGet getRequest = new HttpGet(apiEndpointUrl);
        HttpPost postRequest = new HttpPost(apiEndpointUrl);
        for (Map.Entry<String, String> entry : requestHeaderJson.entrySet()) {
            switch (httpMethod) {
                case ("GET"):
                    getRequest.setHeader(entry.getKey(), entry.getValue());
                    break;
                case ("POST"):
                    postRequest.setHeader(entry.getKey(), entry.getValue());
                    break;
            }
        }
        SSLContext sslContext = null;
        try {
            sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(sslContext,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            CloseableHttpClient client;
            switch (ClientConfig.proxyMode) {
                case (0):
                    config = RequestConfig.custom().build();
                    client = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
                    break;
                case (1):
                    proxyHost = new HttpHost(ClientConfig.proxyHost, ClientConfig.proxyPort);
                    config = RequestConfig.custom().setProxy(proxyHost).build();
                    client = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
                    break;
                case (2):
                    proxyHost = new HttpHost(ClientConfig.proxyHost, ClientConfig.proxyPort);
                    config = RequestConfig.custom().setProxy(proxyHost).build();
                    CredentialsProvider credsProvider = new BasicCredentialsProvider();
                    //Setting the credentials
                    credsProvider.setCredentials(new AuthScope(ClientConfig.proxyHost, ClientConfig.proxyPort),
                            new UsernamePasswordCredentials(ClientConfig.proxyUser, ClientConfig.proxyPassword));
                    client = HttpClients.custom().setSSLSocketFactory(sslcsf).setDefaultCredentialsProvider(credsProvider).build();
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + ClientConfig.proxyMode);
            }
            CloseableHttpResponse response = null;
            switch (httpMethod) {
                case ("GET"):
                    getRequest.setConfig(config);
                    URI uri = getRequestUriParameters(getRequest, requestUriParameters);
                    getRequest.setURI(uri);
                    System.out.println("#a. HTTP Request: " + getRequest.getRequestLine() + "\n#b. HTTP Headers:\n" + Arrays.toString(getRequest.getAllHeaders()) + "\n");
                    response = client.execute(getRequest);
                    break;
                case ("POST"):
                    postRequest.setConfig(config);
                    System.out.println("#a. HTTP Request: " + postRequest.getRequestLine() + "\n#b. HTTP Headers:\n" + Arrays.toString(postRequest.getAllHeaders()) + "\n");
                    postRequest.setEntity(new StringEntity(requestPayload, "UTF-8"));
                    response = client.execute(postRequest);
                    break;
            }
            System.out.println("------ #Processing Response# -----\nHTTP Response Code: " + response.getStatusLine().getStatusCode());
            HttpEntity entity = response.getEntity();
            textToDecrypt = EntityUtils.toString(entity);
            return textToDecrypt;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

Processing a Response

Responses are returned with the relating HTTP code and an encrypted response message.

Processing a Response

Steps to process a response:

String decryptedMessage = processResponseMessage(payloadWrappers, responseMessage, bankPgpPublicKeys, clientPgpPrivateKeys, isVerifySignature);
  1. For a successful response, the response provided will be encrypted and Base64 encoded wrapped in Json Structure
    1. Typically it looks like {"encryptedResponseBase64":"eyJ2ZXIiOiIxL...."}
    2. In some earlier versions of API, there are no payload wrappers. It looks like eyJ2ZXIiOiIxL....
  2. Extract the Base64 representation and decodes it.
  3. Decrypt the decoded payload with your private key.
    1. The decrypted message looks like
      
      {
        "data": {
          "paramKey001": "paramValue001",
          "paramKey002": "paramValue002",
           ...
          }
      }

JAVA Code Example for reference method:

public static String processResponseMessage(HashMap<String, String> payloadWrappers, String responseMessage, List<PGPPublicKey> bankPgpPublicKeys, List<PGPPrivateKey> clientPgpPrivateKeys, Boolean isVerifySignature) {
        String payloadWrapper = payloadWrappers.get("response");
        String textToDecrypt = null;
        String processedMessage = null;

        try {
            boolean isValidJson = isValidJson(responseMessage);
            JSONObject responseMessageJson = new JSONObject(responseMessage);
            if (responseMessageJson.has(payloadWrapper)) {
                textToDecrypt = responseMessageJson.getString(payloadWrapper);
                if (isVerifySignature == true) {
                    System.out.println("  #a.1. Encryption Scheme: Client Public Key Encrypted WITH Bank Private Key Signed\n#a.2. Response Message Schema: EDGE\nEncrypted Base64 String WITH payload wrapper, it is used for API version >=3:");
                } else {
                    System.out.println("  #a.1. Encryption Scheme: Client Public Key Encrypted WITHOUT Bank Private Key Signed\n#a.2. Response Message Schema: EDGE\nEncrypted Base64 String WITH payload wrapper, it is used for API version >=3:");
                }
            }
            else {
                processedMessage = responseMessageJson.toString();
                System.out.println("  #b. Processed Message: \n" + responseMessageJson.toString(4));
                return processedMessage;
            }
        } catch (JSONException jsonException) {
            try {
                boolean isBase64 = MessageLevel.isBase64(responseMessage);
                textToDecrypt = responseMessage;

            } catch (IllegalArgumentException e) {
                return responseMessage;
            }
        }
        processedMessage = decrypt(textToDecrypt, bankPgpPublicKeys, clientPgpPrivateKeys, isVerifySignature);
        try {
            System.out.println("  #b. Processed Message: \n" + new JSONObject(processedMessage).toString(4));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return processedMessage;
    }

public static String decrypt(String textToDecrypt, List<PGPPublicKey> bankPublicKeys,
                                 List<PGPPrivateKey> clientPrivateKeys, boolean isVerifySignature) {
        if (StringUtils.isBlank(textToDecrypt)) {
            return "";
        }
        try {
            ByteArrayOutputStream actualOutput = new ByteArrayOutputStream();
                String epicStrNew = new String(Base64.decode(textToDecrypt));
                JcaKeyFingerprintCalculator keyFingerPrintCalculator = new JcaKeyFingerprintCalculator();
                BufferedInputStream dataStream = new BufferedInputStream(IOUtils.toInputStream(epicStrNew));
                InputStream decoderStream = PGPUtil.getDecoderStream(dataStream);
                PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(decoderStream, keyFingerPrintCalculator);
                PGPEncryptedDataList pgpEncryptedDataList = (PGPEncryptedDataList) pgpObjectFactory.nextObject();
                System.out.println("pgpEncryptedDataList" + pgpEncryptedDataList);
                if (pgpEncryptedDataList != null) {
                    // find the matching public key encrypted data packet.
                    PGPPublicKeyEncryptedData pgpPublicKeyEncryptedData = null;
                    // build decryptor factory
                    PublicKeyDataDecryptorFactory dataDecryptorFactory = null;
                    for (Object pgpEncData : pgpEncryptedDataList) {
                        PGPPublicKeyEncryptedData pkEnc = (PGPPublicKeyEncryptedData) pgpEncData;
                        for (PGPPrivateKey clientPrivateKey : clientPrivateKeys) {
                            if (pkEnc.getKeyID() == clientPrivateKey.getKeyID()) {
                                pgpPublicKeyEncryptedData = pkEnc;
                                dataDecryptorFactory = new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC")
                                        .build(clientPrivateKey);
                                break;
                            }
                        }
                    }
                    if (pgpPublicKeyEncryptedData == null || dataDecryptorFactory == null) {
                        // Public key used to encrypt data does not correspond to private key provided
                        throw new IllegalStateException("matching encrypted data not found");
                    }
                    InputStream clear = pgpPublicKeyEncryptedData.getDataStream(dataDecryptorFactory);
                    PGPObjectFactory plainFact = new PGPObjectFactory(clear, new JcaKeyFingerprintCalculator());
                    Object message = plainFact.nextObject();
                    // Signature related
                    PGPSignatureList signatureList = null;
                    PGPOnePassSignatureList onePassSignatureList = null;
                    PGPCompressedData compressedData = null;
                    while (message != null) {
                        if (message instanceof PGPCompressedData) {
                            compressedData = (PGPCompressedData) message;
                            plainFact = new PGPObjectFactory(compressedData.getDataStream(), keyFingerPrintCalculator);
                            message = plainFact.nextObject();
                        }
                        if (message instanceof PGPLiteralData) {
                            // have to read it and keep it somewhere.
                            Streams.pipeAll(((PGPLiteralData) message).getInputStream(), actualOutput);
                        } else if (message instanceof PGPOnePassSignatureList) {
                            onePassSignatureList = (PGPOnePassSignatureList) message;
                        } else if (message instanceof PGPSignatureList) {
                            signatureList = (PGPSignatureList) message;
                        } else {
                            throw new PGPException("message unknown message type.");
                        }
                        message = plainFact.nextObject();
                    }
                    // check data decrypts okay
                    if (!pgpPublicKeyEncryptedData.verify()) {
                        throw new RuntimeException("Enc data is invalid!");
                    }
                    if (isVerifySignature != true) {
                        actualOutput.close();
                        clear.close();
                        return actualOutput.toString();
                    } else {
                        if (onePassSignatureList == null || signatureList == null) {
                            throw new SignatureException("PGP Signatures not found.");
                        } else {
                            boolean signatureVerified = false;
                            for (int i = 0; i < onePassSignatureList.size(); i++) {
                                PGPOnePassSignature ops = onePassSignatureList.get(0);
                                PGPSignature signature = signatureList.get(0);
                                for (PGPPublicKey bankPublicKey : bankPublicKeys) {
                                    ops.init(new JcaPGPContentVerifierBuilderProvider().setProvider(new BouncyCastleProvider()),
                                            bankPublicKey);
                                    ops.update(actualOutput.toByteArray());
                                    if (ops.verify(signature)) {
                                        signatureVerified = true;
                                        break;
                                    }
                                }
                            }
                            if (!signatureVerified) {
                                throw new SignatureException("Signature verification failed");
                            }
                        }
                        actualOutput.close();
                        clear.close();
                    }
                    return actualOutput.toString();
                }
                return epicStrNew;

        } catch (PGPException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

 

Return to top