Token Vault
Webhook Integration

Request Authentication

How Token Vault authenticates webhook requests using HMAC-SHA256 signatures with replay prevention.

Signature Flow

Loading diagram...

Every request from Token Vault (except /v1/exchange) includes three headers for authentication and replay prevention:

Request Headers
X-TokenVault-Signature: sha256=<HMAC-SHA256 hex digest>
X-TokenVault-Timestamp: <Unix timestamp in seconds>
X-TokenVault-Request-Id: req_<12-char hex>
Content-Type: application/json

Signature Verification

The signed payload is {timestamp}.{json_body}, HMAC-SHA256'd with the shared secret established during /v1/exchange.

Verification pseudocode
# 1. Extract headers
signature = request.headers["X-TokenVault-Signature"]  # "sha256=abc123..."
timestamp = request.headers["X-TokenVault-Timestamp"]   # "1708300000"
raw_body = request.body                                  # raw JSON bytes

# 2. Compute expected signature
signing_payload = f"{timestamp}.{raw_body.decode('utf-8')}"
expected = hmac_sha256(hmac_secret, signing_payload.encode("utf-8")).hexdigest()

# 3. Compare using constant-time comparison
if not constant_time_compare(expected, signature[7:]):  # strip "sha256=" prefix
    return 401  # Reject: signature invalid

Use raw bytes for verification

Token Vault serializes the request body as compact JSON with no whitespace (json.dumps(body, separators=(",", ":"))). Your HMAC verification must use the raw bytes received. Do not re-serialize or pretty-print the body before computing the signature.

Replay Prevention

  • Timestamp check: Reject requests where the timestamp is more than 5 minutes from the current time.
  • Request ID deduplication: Track X-TokenVault-Request-Id values to prevent duplicate processing.

Exceptions

Two endpoints do not require HMAC authentication:

  • POST /v1/exchange - Called before the HMAC secret exists. Authentication is via the one-time exchange code.
  • GET /v1/health - Unauthenticated GET requests are allowed for external monitoring, load balancers, and the /bind status page. The POST /v1/health variant remains HMAC-signed.

All other endpoints must verify the HMAC signature.

On this page