Skip to main content
To ensure the security and integrity of every request, The Dispersed API uses an HMAC (Hash-based Message Authentication Code) signature. This proves you possess the secret key without ever transmitting it over the network.

Required Headers

Every API request must include these four headers:

Authentication: HMAC Signature Scheme

Dispersed API requests require HMAC-SHA256 authentication, constructed by signing a 7-part, pipe-delimited canonical string (publicKey|timestamp|nonce|METHOD|pathname|queryString|bodySha256). Key requirements include sorting query parameters alphabetically (without the leading ”?”), hashing the body with SHA-256 (using an empty string hash for empty bodies), and creating a 64-character lowercase hex signature from the final string. The signature proves you possess the secret key without transmitting it.

Steps to build the HMAC Signature

1. Build the Canonical String

The “Canonical String” is a standardized version of your request. You must concatenate exactly seven components using the pipe (|) character as a delimiter.
Example:

Rules For The Query String (No Leading ?)

The queryString component should contain only the data parameters.
  • DO: limit=10&sort=desc
  • DON’T: ?limit=10&sort=desc (The ? is a separator for the URI, not part of the data).

Handling Empty Fields (||)

If a component is empty (common with queryString or bodySha256), you must still include the pipe delimiter. This maintains the “column” structure of the string.
  • Example of an empty query string: ...|METHOD|pathname||bodySha256
  • The || indicates that the 6th component is an empty string.

Sort Query Parameters

To ensure deterministic signatures:
  1. Sort parameter keys alphabetically (lexicographic order)
  2. For duplicate keys, sort their values alphabetically
  3. URL-encode keys and values
  4. Join with & (no leading ?)
Example: ?z=3&a=1&b=2 becomes a=1&b=2&z=3 Multi-value example: ?tag=zebra&tag=apple becomes tag=apple&tag=zebra

Complete Examples

Target URI: https://example.comResulting Canonical String:
Target URI: https://example.comResulting Canonical String:
(Note the || where the query string would normally be.)

2. Canonicalize the Request Body

Turn a “messy” JSON object into a single, predictable string so that a hash can be calculated. For JSON bodies (Content-Type: application/json):
  1. Parse the JSON. Before you can secure the data, you must turn it into a “clean” data structure so that your code can manipulate it.
  2. Re-serialize with:
    • Keys sorted alphabetically (recursive for nested objects): Original: {"status": "active", "id": 101} Sorted: {"id": 101, "status": "active"} Recursive: If there is an object inside the object, you must sort those keys too.
    • Compact format (no whitespace): {"key":"value"} not { "key": "value" } Human-readable JSON has spaces and newlines. Computers don’t need them. You must strip all “extra” characters. (Note: No spaces after colons or commas.)
    • ASCII-safe encoding If you have special characters (like emojis or non-English letters), you must ensure they are encoded consistently (usually using \u escapes for non-ASCII or just standard UTF-8 bytes) so the hash does not change based on the computer’s language settings.
  3. Compute SHA-256 hash of the UTF-8 encoded result
Example: { "z": 1, "a": 2 } becomes {"a":2,"z":1} For empty bodies (GET, DELETE, or POST with no body), hash an empty byte array:

3. Sign with HMAC-SHA256

Once you have built the compact, sorted Canonical String, use your Secret Key to sign it using the HMAC-SHA256 algorithm. Your secret key (sk_...) is used to compute the HMAC-SHA256 signature of the canonical string. Output as lowercase hex (64 characters) and pass the resulting hex string in your request headers as X-Signature.

Code Examples


Common Errors


Troubleshooting Signatures

If you’re getting “Invalid signature” errors, verify each component of the canonical string:

Checklist

  1. Timestamp precision
    • Must be milliseconds, not seconds
    • Example: 1706918400000 (13 digits), not 1706918400 (10 digits)
  2. Nonce format
    • Exactly 32 lowercase hex characters (representing 16 random bytes)
    • Use cryptographic random: crypto.randomBytes(), secrets.token_hex(), or crypto/rand
    • Example: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
  3. Body canonicalization
    • JSON keys sorted recursively (nested objects too)
    • Compact format with no whitespace: {"a":1,"b":2} not { "a": 1, "b": 2 }
    • Use separators=(",", ":") in Python, compact marshaling in Go/TypeScript
  4. Query string canonicalization
    • Sort both keys and values alphabetically
    • No leading ? character
    • Use RFC 3986 percent-encoding (spaces as %20, not +)
    • Example: ?z=3&a=1a=1&z=3
  5. Empty body handling
    • Hash an empty byte array, not null or undefined
    • SHA-256 of empty: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  6. Pathname normalization
    • No trailing slashes (except root /)
    • Collapse multiple slashes: //api//v1/api/v1
    • No query string (that’s a separate component)
  7. Encoding
    • UTF-8 for all strings
    • Lowercase hex for SHA-256 hash and signature

Debug Your Canonical String

Print your canonical string before signing to verify each component:
Ensure there are exactly 7 components separated by 6 pipe characters.
Keep it Secret, Keep it Safe
  • Preferred: Store secret keys in a dedicated secrets manager (AWS Secrets Manager, HashiCorp Vault, Google Secret Manager, Azure Key Vault)
  • Alternative: Use environment variables if a secrets manager is not available (NOTE: environment variables can be exposed through process listings, logs, or crash dumps)
  • Never hardcode keys in source code or commit them to version control
  • Use cryptographically secure random number generators for nonces
  • Implement request timeouts to prevent hanging connections
  • Rotate API keys periodically and revoke unused keys promptly