🔐 HMAC Signature and Authorization Workflow Guide
This guide explains how to securely authenticate requests using HMAC signatures in the TokenCity Blockchain API. It includes how to compute the signature, apply it to outgoing or incoming requests, and how to validate it in webhook or client-side flows.
🧩 What is HMAC Authentication?
HMAC (Hash-based Message Authentication Code) is a cryptographic mechanism used to verify the integrity and authenticity of a message. In this API, HMAC is used to sign and validate both:
- 🔁 Outgoing webhook notifications
- 📤 Client requests to secure endpoints
✨ HMAC Signature Generation
The HMAC signature is computed using:
- A shared secret key (provided during API client setup).
- A message body, typically the full raw request body.
🔐 Algorithm
HMAC-SHA256
🔣 Header Format
Add the following HTTP header to your request or webhook handler:
Signature: TC sha256 {GeneratedSignature}
Date: Tue, 10 Jun 1999 14:17:50 GMT
Authorization: {HMAC-KeyID}
👨💻 Code Snippet
function calculateHmacSignature(
hmacKeyId: string,
hmacSecretKey: string,
date: string,
url: string,
paylaod: string,
method = "POST",
reqQuery?: any[]
) {
let encodedQueryParams;
if (reqQuery) {
const queryParams: { key: string; value: string }[] = [];
for (const query in reqQuery) {
queryParams.push({
key: query,
value: reqQuery[query],
});
}
queryParams.sort((a, b) => {
return a.key.localeCompare(b.key);
});
encodedQueryParams = queryParams.reduce((pv, cv, i) => {
if (i == queryParams.length - 1)
return pv + `${cv.key.toLowerCase()}=${cv.value.trim()}`;
return pv + `${cv.key.toLowerCase()}=${cv.value.trim()}&`;
}, "");
}
const headers: { key: string; value: string }[] = [
{
key: "authorization",
value: hmacKeyId,
},
{
key: "date",
value: date,
},
];
const encodedHeaders = headers.reduce((pv, cv, i) => {
if (i == headers.length - 1)
return pv + `${cv.key.toLowerCase()}:${cv.value.trim()}`;
return pv + `${cv.key.toLowerCase()}:${cv.value.trim()}\n`;
}, "");
const contentBytes = CryptoJS.enc.Utf8.parse(paylaod);
const contentHash = CryptoJS.SHA256(contentBytes);
const queryParams = encodedQueryParams ?? "";
const payload =
method +
"\n" +
new URL(url).pathname +
"\n" +
queryParams +
"\n" +
encodedHeaders +
"\n" +
contentHash;
const signatureBytes = CryptoJS.HmacSHA256(payload, hmacSecretKey);
const signature = CryptoJS.enc.Base64.stringify(signatureBytes);
return signature;
}