Skip to main content

Secure API Request Signing and Idempotency Mechanism

Overview

🧩 This API leverages a robust security mechanism involving HMAC-based request signing, timestamping, unique request identification (nonce), and idempotency keys. These mechanisms collectively ensure the integrity, authenticity, and non-replayability of client requests, as well as safe handling of duplicate submissions. 📘 This documentation explains each mechanism, their purposes, and how to implement the required client logic (e.g., in Postman or custom API clients).

1. HMAC Signature (X-Signature Header)

What is it?

🔑 An HMAC (Hash-based Message Authentication Code) is a cryptographic signature generated using a shared secret and the request data. It ensures that the request cannot be tampered with, and its sender can be authenticated.

Purpose

  • Integrity 🛡️: Detects if any part of the request (method, URI, body, timestamp) has been altered.
  • Authentication 🔐: Confirms the request is from a trusted client who knows the secret key.
  • Anti-Replay ♻️: Tied to a timestamp and unique values, making replay attacks detectable.

How is it used?

  • The client constructs a string to sign, concatenating the HTTP method, full request path (including query), current timestamp in epoch milliseconds, and resolved request body 🧾:
dataToSign = HTTP_METHOD + "|" + PATH_WITH_QUERY + "|" + TIMESTAMP + "|" + BODY
  • The client generates the HMAC SHA256 signature using the shared secret (kept in a secure vault, never exposed) 🔒:
X-Signature = HMAC_SHA256(secret, dataToSign)
  • This signature is sent in the request header X-Signature 🚀.
⚠️ Please ask us HMAC Secret before making your first API call.

What if not used?

  • Client will receive an error message with http status 400 - Bad Request
{
  "timestamp": "2025-04-14T16:58:10.414972912",
  "status": 400,
  "error": "Bad Request",
  "message": "Missing signature, timestamp, or nonce headers",
  "path": "/auth/login"
}

What if signature is not valid?

  • Client will receive an error message with http status 401 - Unauthorized
{
  "timestamp": "2025-04-14T16:57:50.083970026",
  "status": 401,
  "error": "Unauthorized",
  "message": "Invalid request signature",
  "path": "/auth/login"
}

2. Timestamp (X-Timestamp Header)

What is it?

⏱️ The Unix timestamp (in milliseconds) at the moment the request is generated.

Purpose

  • Anti-Replay 🛑: Prevents an attacker from reusing a previously valid request, since the server can enforce strict time windows for valid requests.

How is it used?

  • The client generates the timestamp just before sending the request and includes it as the X-Timestamp header ⌚.

What if not used?

  • Client will receive an error message with http status 400 - Bad Request
{
  "timestamp": "2025-04-14T16:58:10.414972912",
  "status": 400,
  "error": "Bad Request",
  "message": "Missing signature, timestamp, or nonce headers",
  "path": "/auth/login"
}

3. Nonce (X-Nonce Header)

What is it?

🎲 A nonce is a randomly generated unique identifier (UUID v4) included in each request.

Purpose

  • Anti-Replay 🔁: Further prevents request replay by uniquely identifying each request. Even if method, URI, and body are the same, the nonce will differ.

How is it used?

  • The client generates a new UUID v4 for every request and includes it as the X-Nonce header 🎯.

What if not used?

  • Client will receive an error message with http status 400 - Bad Request
{
  "timestamp": "2025-04-14T16:58:10.414972912",
  "status": 400,
  "error": "Bad Request",
  "message": "Missing signature, timestamp, or nonce headers",
  "path": "/auth/login"
}

What if re-used?

  • Client will receive an error message with http status 409 - Conflict
{
  "timestamp": "2025-04-14T16:57:21.168927321",
  "status": 409,
  "error": "Conflict",
  "message": "Replay attack detected (nonce reused)",
  "path": "/endpoint/uri/here"
}

4. Idempotency Key (X-Idempotency-Key Header)

What is it?

🪪 A unique identifier (UUID v4) for each request, enabling the server to recognize and safely ignore duplicate submissions (e.g., from retrying a POST request).

Purpose

  • Idempotency 🔂: Guarantees that retrying a request due to network errors will not result in duplicate resource creation or side effects.

How is it used?

  • The client generates a new UUID v4 for each operation and sends it as the X-Idempotency-Key header 📮.

What if not used?

  • Client will receive an error message with http status 400 - Bad Request
{
  "timestamp": "2025-04-14T16:26:54.203118461",
  "status": 400,
  "error": "Bad Request",
  "message": "Missing X-Idempotency-Key header",
  "path": "/endpoint/uri/here"
}

What if re-used?

  • Client will receive an error message with http status 409 - Conflict
{
  "timestamp": "2025-04-14T16:56:28.671809875",
  "status": 409,
  "error": "Conflict",
  "message": "Duplicate request detected (X-Idempotency-Key)",
  "path": "/endpoint/uri/here"
}

Security Considerations

  • The secret used for HMAC must never be shared or exposed in client code or documentation 🔐.
  • Always use HTTPS to prevent man-in-the-middle attacks 🌐.
  • Servers enforce a maximum allowable time skew for the X-Timestamp and reject used/replayed X-Nonce or X-Idempotency-Key values within a certain window ⛔.

Example Headers

X-Signature: 75c759570bbb5dfd40136cffd3dbaa51b28d4620e51359161686790adcc53bea
X-Timestamp: 1752751106704
X-Nonce: 684a0dca-bd6a-4056-a449-2567f9847f9c
X-Idempotency-Key: 777edc03-ad49-4c17-be6b-9baf05a1b9e0

Summary Table 📊

HeaderValue/FormatPurpose
X-SignatureHexadecimal stringRequest authenticity/integrity
X-TimestampMilliseconds since epochPrevent replay
X-NonceUUID v4Uniqueness/anti-replay
X-Idempotency-KeyUUID v4Idempotency for retries