hooksig / DocuSign
HMAC-SHA256 · base64 · no timestamp
DocuSign
DocuSign Connect signs like Shopify, base64 over the raw body, and rotates keys across numbered headers.
Try it, live in your browser
Request: edit anything
Verify this in code
import { verify } from "hooksig";
const result = await verify("docusign", {
payload: rawBody, // the RAW body, not parsed JSON
headers: request.headers,
secret: env.WEBHOOK_SECRET,
});
if (!result.verified) {
return new Response(result.reason, { status: 400 });
}no match: signature invalid
Signed string
HMAC-SHA256( secret, signed string ) = expected
Expected vs provided
expected
provided
How it's built
The scheme
- Header
X-DocuSign-Signature-1 - AlgorithmHMAC-SHA256
- Encodingbase64
- Timestampnone, add your own if you need it
- SignsHMAC-SHA256 over the raw body, base64-encoded, keyed by the Connect HMAC secret. No timestamp.
Gotchas
- The digest is base64, not hex.
- Strip any literal double-quote characters from the HMAC secret before using it as the key.
- During key rotation DocuSign sends X-DocuSign-Signature-1, -2, and so on, one per active key. Any single header matching is valid; this checks -1.
- Sign the RAW body exactly as received. No timestamp is signed, so add your own replay protection if you need it.