← Back to Index

HMAC Authentication Guide

This document describes the HMAC-SHA256 signature-based authentication used by the gate.hyperapify.com API gateway.

Overview

Every request must include two headers:

HeaderDescription
DateCurrent UTC time in GMT string format. Server allows up to 300s clock skew.
AuthorizationSignature header with keyId, algorithm, signed headers, and base64 signature.
Digest (optional)Required only when a request body is present. SHA-256 hash of the body.

Supported Algorithms

AlgorithmValue
HMAC-SHA1hmac-sha1
HMAC-SHA256hmac-sha256
HMAC-SHA512hmac-sha512

Authentication Flow

Step 1: Build the signing string
signingString = keyId + "\n"
               + METHOD + " " + requestPath + "\n"
               + "date: " + gmtTime + "\n"

requestPath must include the full URL-encoded query string if present.
Example: /fdb-hub/fetch_search_posts?query=g%C3%A1i+%C4%91%E1%BA%B9p

Step 2: Create HMAC signature
signature = HMAC-SHA256(secretKey, signingString)
signatureBase64 = base64(signature)
Step 3: Build Authorization header
Authorization: Signature keyId="YOUR_KEY_ID",algorithm="hmac-sha256",headers="@request-target date",signature="BASE64_SIGNATURE"
Step 4 (if body exists): Add Digest header
bodyDigest = base64(SHA-256(requestBody))
Digest: SHA-256=BODY_DIGEST_BASE64

Input Parameters

ParameterTypeDescription
keyIdstringYour API key identifier (provided by the gateway)
secretKeystringYour secret key for HMAC signing (UTF-8 encoded)
requestMethodstringHTTP method: GET, POST, PUT, DELETE, etc.
requestPathstringFull path including URL-encoded query string
bodystring | undefinedRequest body (JSON string for POST requests)

JavaScript Example

import crypto from "crypto";

const keyId = "your-key-id";
const secretKey = Buffer.from("your-secret-key", "utf-8");
const requestMethod = "GET";

// Build full request path with encoded query params
const params = new URLSearchParams({ query: "search term" });
const baseUrl = new URL("/fdb-hub/fetch_search_posts", "https://gate.hyperapify.com");
baseUrl.search = params.toString();
const requestPath = baseUrl.pathname + baseUrl.search;

// Step 1: Signing string
const gmtTime = new Date().toUTCString();
const signingString =
  keyId + "\n" +
  requestMethod + " " + requestPath + "\n" +
  "date: " + gmtTime + "\n";

// Step 2: HMAC-SHA256 signature
const signature = crypto
  .createHmac("sha256", secretKey)
  .update(signingString, "utf-8")
  .digest();
const signatureBase64 = signature.toString("base64");

// Step 3: Headers
const headers = {
  Date: gmtTime,
  Authorization:
    'Signature keyId="' + keyId + '",' +
    'algorithm="hmac-sha256",' +
    'headers="@request-target date",' +
    'signature="' + signatureBase64 + '"',
};

// Step 4 (optional): Body digest for POST requests
// const body = '{"key": "value"}';
// const bodyDigest = crypto.createHash("sha256")
//   .update(body, "utf-8").digest().toString("base64");
// headers["Digest"] = "SHA-256=" + bodyDigest;

// Send request
const res = await fetch(baseUrl.toString(), {
  method: requestMethod,
  headers,
});
Note: The server allows requests up to 300 seconds behind the current time. Ensure your system clock is synchronized.

Common Errors

ErrorCause
401 UnauthorizedInvalid signature, wrong keyId, or expired Date header (>300s skew)
400 Bad RequestMissing required headers (Date, Authorization) or malformed Digest