MPC-TSS
Authorization

Authorization

This secion provides details on how to authorize your API requests using custom headers. The authorization relies on three headers: X-SIGNATURE, X-TIMESTAMP, and X-CLIENT-ID. Follow the steps below to securely access the API.


HTTP headers

To authenticate a request, include the following headers in your API request:

HeaderDescription
X-SIGNATUREA signature generated using HMAC-SHA256.
X-TIMESTAMPThe request timestamp in RFC3339 format.
X-CLIENT-IDClient ID generated when register in Xellar TSS API Service Dashboard.

How to Generate the Signature

The signature is generated using the following formula:

stringToSign = ${method}:${url}:${minifiedJSON}:${timestamp}
signature = HMAC-SHA256(stringToSign, clientSecret)

Components of stringToSign:

  • method: The HTTP method (e.g., POST, GET, etc.). Uppercase
  • url: API Endpoint URL Path
  • minifiedJSON: Request payload in minified JSON format. Hash with sha-256, then make it lowercase. lower(sha256(minify(JSONRequestBody)))
  • timestamp: The current timestamp in RFC3339 format (e.g., 2024-11-19T12:34:56Z). This value must be same as X-TIMESTAMP header.

Example stringToSign

Method        : GET
URL           : /api/v1/wallet/check/544f7d79
Request Body  : -
Timestamp     : 2024-11-20T10:48:02+07:00
Client Secret : your-client-secret-from-the-dashboard
-----------------------------------------
minifiedJSON    : lower(sha256(""))
String To Sign  : GET:/api/v1/wallet/check/544f7d79:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855:2024-11-20T10:48:02+07:00
Signature       : VKPH47xJppCxQSG5fLQ0yPoCesFxyH05Jg7YLLgB0Gc=
Method        : POST
URL           : /api/v1/wallet/account
Request Body  : { "subId": "8b6aae63-cb8d-495d-9102-cc46b052aba1"}
Timestamp     : 2024-11-20T10:49:12+07:00
Client Secret : your-client-secret-from-the-dashboard
-----------------------------------------
minifiedJSON    : lower(sha256("{\"subId\":\"8b6aae63-cb8d-495d-9102-cc46b052aba1\"}"))
String To Sign  : POST:/api/v1/wallet/account:18c58628ca72ad1900e4ba4f18c2daf64b88d930d978714d385dbdbe5e496319:2024-11-20T10:49:12+07:00
Signature       : a6Nc4MvfpQsmDytOATTP1gKlpe8ww7HtrSr9+gJPYfM=

Example Implementation

const crypto = require('crypto');
 
/**
 * Minifies a JSON string by removing unnecessary spaces.
 */
function minifiedJSON(inputJSON) {
    if (!inputJSON) {
        return "";
    }
    try {
        const parsed = JSON.parse(inputJSON);
        return JSON.stringify(parsed); // Minified JSON
    } catch (error) {
        throw new Error(`Invalid JSON input: ${error.message}`);
    }
}
 
/**
 * Hashes the minified JSON using SHA256 and converts it to lowercase.
 */
function hashMinifiedJSON(inputJSON) {
    const minified = minifiedJSON(inputJSON);
    const hash = crypto.createHash('sha256').update(minified).digest('hex');
    return hash.toLowerCase();
}
 
/**
 * Generates the HMAC signature using the provided inputs.
 */
function generateSignature(method, url, clientSecret, hashedMinifiedJSON, timestamp) {
    const stringToSign = `${method.toUpperCase()}:${url}:${hashedMinifiedJSON}:${timestamp}`;
    const hmac = crypto.createHmac('sha256', clientSecret).update(stringToSign).digest();
    return hmac.toString('base64');
}
 
/**
 * Prepares headers for an authorized request.
 */
function prepareHeaders(method, url, clientId, clientSecret, requestBody) {
    const timestamp = new Date().toISOString(); // RFC3339 format
 
    // Hash the minified JSON
    const hashedMinifiedJSON = hashMinifiedJSON(requestBody);
 
    // Generate signature
    const signature = generateSignature(method, url, clientSecret, hashedMinifiedJSON, timestamp);
 
    // Prepare headers
    return {
        'Content-Type': 'application/json',
        'X-TIMESTAMP': timestamp,
        'X-CLIENT-ID': clientId,
        'X-SIGNATURE': signature,
    };
}
 
// Example usage
const method = "POST";
const url = "/api/v1/wallet/account";
const clientId = "your-client-id-from-the-dashboard";
const clientSecret = "your-client-secret-from-the-dashboard";
const requestBody = '{"subId": "8b6aae63-cb8d-495d-9102-cc46b052aba1"}';
 
try {
    const headers = prepareHeaders(method, url, clientId, clientSecret, requestBody);
    console.log(headers);
} catch (error) {
    console.error(`Error: ${error.message}`);
}