API Documentation

Securing API Requests

v1.0.0

To maintain secure and verified communication between systems, all requests made between our API and operators must adhere to the following security requirements. The specifics below outline how requests should be validated, whether initiated by the API or the operator.

Security Requirements for API Requests

For requests originating from our API to operators, operators should validate each incoming request by checking the following headers. Similarly, operators should add these headers to requests they initiate to our API.

Required Headers for Request Validation

Each secured request must contain the following headers:

  1. X-Art-Client-ID: A unique identifier for the operator, provided by us.
  2. X-Art-Client-TS: A timestamp in UTC, representing seconds since the Unix Epoch.
  3. X-Art-Client-Signature: A hashed signature that verifies the integrity of the request parameters.

Generating the X-Art-Client-Signature Header

The X-Art-Client-Signature ensures request authenticity by following these steps to create a signature:

  1. Concatenate the following values: Timestamp (X-Art-Client-TS): Timestamp at the time of the request. Request URI: URL path with ordered and encoded query parameters (without the domain). Request Body: For POST and PUT requests, include the request body as a string. Omit this for GET and DELETE requests.
  2. Hash the concatenated string: Use the SHA256 HMAC algorithm, with the operator's Client Secret as the key, to hash the concatenated string.

Important!

When generating the HMAC-SHA-256 signature, the JSON string used must have parameters in the exact same order as in the request body. Changing the field order will result in a different hash.

Validation Process

Upon receiving a request, the server (operator's or ours) should validate the X-Art-Client-Signature by:

  1. Retrieving the Client Secret based on X-Art-Client-ID.
  2. Repeating the signature creation process using the headers and parameters.
  3. Comparing the generated signature to the received X-Art-Client-Signature header. A match indicates the request is verified.

Example Implementation for Incoming API Requests

Below is an example illustrating how to implement secure request handling on the operator's side or ours:

java
@PostMapping(path = "/secure-request")
public ResponseEntity<Void> secureRequest(@RequestBody final byte[] body,
                                          @RequestHeader(name = "X-Art-Client-ID") final String clientId,
                                          @RequestHeader(name = "X-Art-Client-TS") final long time,
                                          @RequestHeader(name = "X-Art-Client-Signature") final String signature,
                                          final HttpServletRequest request) {
    // Validate headers and timestamp expiration
    final var clientSecret = getClientSecretFromRepository(clientId); // Retrieve Client Secret
    final var queryString = request.getQueryString();
    final var path = request.getRequestURI() + (queryString == null || "".equals(queryString) ? "" : "?" + request.getQueryString());
    final var calculatedSignature = createSignature(time, path, body, clientSecret);
     
    if (!signature.equalsIgnoreCase(calculatedSignature)) {
        throw new SecurityException("Signature mismatch.");
    }
}
 
public static String createSignature(final long time, final String path, final byte[] body, final String clientSecret) {
    try {
        Mac sha256Hmac = Mac.getInstance("HmacSHA256");
        sha256Hmac.init(new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        sha256Hmac.update((time + path).getBytes(StandardCharsets.UTF_8));
         
        byte[] bytes = body == null ? sha256Hmac.doFinal() : sha256Hmac.doFinal(body);
        return HexFormat.of().formatHex(bytes);
    } catch (Exception e) {
        throw new SecurityException("Error creating signature.", e);
    }
}

This structure clarifies that both the operator and the API system are responsible for including and validating security headers on their outgoing and incoming requests, ensuring consistent security standards across all communications.