# Signature Calculation This document describes the HMAC-SHA256 signature calculation process used for API authentication. The signature is generated by combining the request URL, query parameters, and request body into a signature string, then computing an HMAC-SHA256 hash using a secret key. **Algorithm**: HMAC-SHA256
**Encoding**: Base64
**Signature Header**: X-App-Signature
## Signature Generation Process

Step 1: Extract Request Components

1. **URL**: Extract the base URL (without query parameters) 2. **Query Parameters**: Extract all enabled query parameters 3. **Request Body**: Process the request body content

Step 2: Build Signature String

The signature string is constructed by concatenating the following components with `&` as separator: ```curl signature_string = URL + "&" + sorted_query_params + "&" + request_body ```

2.1 URL Processing

- Use the base URL without query parameters - Example: `https://api.example.com/v1/orders`

2.2 Query Parameters Processing

- Extract all enabled query parameters - Sort parameters by key name (alphabetical order) - Format each parameter as `key=value` - Join multiple parameters with `&` - Handle null/undefined values as empty strings **Example:** ```curl Original parameters: {c: "3", a: "1", b: "2"} Sorted result: a=1&b=2&c=3 ```

2.3 Request Body Processing

- JSON Format: Use JSON string directly - Null Value Handling: Empty objects `{}` or empty strings will be skipped - Type Conversion: Non-string types will be converted to JSON strings

Step 3: Calculate HMAC-SHA256 Signature

1. Use the constructed signature string as the message 2. Use the provided secret key 3. Calculate HMAC-SHA256 hash 4. Encode the result in Base64 format ## Examples

Example 1: GET Request with Query Parameters

**Request:** ``` curl URL: https://api.example.com/v1/users Query Parameters: {page: "2", limit: "10", sort: "name"} Body: (empty) ``` **Signature String:** ``` curl https://api.example.com/v1/users&limit=10&page=2&sort=name ```

Example 2: POST Request with JSON Body

**Request:** ``` curl URL: https://api.example.com/v1/orders Query Parameters: (empty) Body: {"userId": 123, "productId": 456, "quantity": 2} ``` **Signature String:** ``` curl https://api.example.com/v1/orders&{"userId":123,"productId":456,"quantity":2} ```

Example 3: PUT Request with Both Query Parameters and Body

**Request:** ```curl URL: https://api.example.com/v1/products Query Parameters: {version: "v2", format: "json"} Body: {"name": "Product A", "price": 99.99} ``` **Signature String:** ```curl https://api.example.com/v1/products&format=json&version=v2&{"name":"Product A","price":99.99} ``` ## Signature calculation script example - Below is a complete calculation script example of the signature (**JAVA**). You can refer to it to implement the signature calculation script of your development language. ```java import org.apache.commons.lang.StringUtils; 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.Map; import java.util.TreeMap; public class SignatureUtils { /** * generate signature * @param url: request url * @param queryParamMap: request query parameters Map Structure * @param bodyJSONString: request body JSON String * @param clientSecret: client secret * @return */ public String generateSignature(String url, Map queryParamMap, String bodyJSONString, String clientSecret) { StringBuilder sb = new StringBuilder(); // step 1: concat url sb.append(url); // step 2: concat query parameters if (!queryParamMap.isEmpty()) { // 2.1: sort by alphabetical order TreeMap sortedParams = new TreeMap<>(queryParamMap); // 2.2: concat key and value for (Map.Entry entry : sortedParams.entrySet()) { String key = entry.getKey(); String value = entry.getValue() != null ? entry.getValue().toString() : null; sb.append("&"); sb.append(key + "=" + value); } } // step 3: concat body if (StringUtils.isNotBlank(bodyJSONString)) { sb.append("&"); sb.append(bodyJSONString); } // step 4: got a complete string waiting to generate a signature String signatureString = sb.toString(); try { // step 5: initialize the HmacSHA256 algorithm with the clientSecret Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); // step 6: calculate signature byte[] bytes = mac.doFinal(signatureString.getBytes(StandardCharsets.UTF_8)); // step 7: encode the signature in Base64 format String signature = new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8); return signature; }catch (NoSuchAlgorithmException e){ throw new IllegalStateException("Algorithm HmacSHA256 does not exist.", e); }catch (InvalidKeyException e){ throw new RuntimeException("Key is invalid.", e); } } } ``` ## Signature tools You can easily calculate the correct signature through this tool, helping you quickly verify whether your code implementation is correct. >>> Click here