Code snippets for verifying the HMAC-SHA1 signature that Autodesk Platform Services (APS) attaches to every webhook delivery.
Implementing signature verification protects your webhook endpoint from spoofed requests: only payloads that were genuinely sent by APS (and have not been tampered with in transit) will produce a matching signature.
┌────────────┐ POST /webhook ┌────────────────┐
│ APS │ ─────────────────────────────────────► │ Your server │
│ (sender) │ Headers: │ (receiver) │
│ │ x-adsk-signature: sha1hash=<hex> │ │
│ │ Body: <raw JSON payload> │ │
└────────────┘ └────────────────┘
- APS computes
HMAC-SHA1(raw_body, webhook_secret)using the secret you chose when creating the webhook subscription. - APS hex-encodes the result and sends it in the
x-adsk-signatureheader with the prefixsha1hash=. - You save the raw payload to
sample.jsonand thex-adsk-signatureheader value toRECEIVED_HASHin the.envfile. - The CLI tool reads the raw bytes of the payload and re-computes the same HMAC using the same secret.
- It compares the two values with a constant-time (timing-safe) comparison function to prevent timing-based attacks.
- If they match the payload is authentic.
Important: The payload in
sample.jsonmust be the exact raw bytes received. Do not re-format or re-serialize the JSON, as even whitespace changes will break the HMAC comparison.
If the signature comes back as INVALID, check the following:
| Issue | Symptom | Fix |
|---|---|---|
| Line endings | On Windows, editors save files with CRLF (\r\n), but APS sends payloads with LF (\n). The extra \r bytes change the HMAC entirely. |
The CLI tools automatically normalize CRLF to LF before computing the hash. If you process the payload in your own code, make sure to do the same. |
| Reformatted JSON | Pretty-printing, re-serializing, or minifying the payload changes whitespace, key order, or numeric formatting. | Always use the raw body bytes exactly as received. Do not run the JSON through a parser/serializer round-trip. APS (Java/Jackson) sends payloads with " : " separators and 2-space indentation -- preserve that format. |
| Wrong secret | The WEBHOOK_SECRET in .env doesn't match the secret used when the webhook subscription was created in APS. |
Double-check the secret in the APS Webhooks dashboard. |
| Truncated or modified payload | The payload was edited, truncated, or had extra characters added after being captured. | Compare the byte length reported by the tool against the Content-Length header from the original delivery. |
| Folder | Language / Tool | Description |
|---|---|---|
python/ |
Python 3.8+ | Reusable helper function + CLI verification tool |
javascript/ |
Node.js 18+ | Reusable helper function + CLI verification tool |
csharp/ |
C# / .NET 8 | Reusable static helper class + CLI verification tool |
Each folder contains its own README.md with setup instructions and
integration guidance.
- Copy
.env.exampleto.envin the repo root and fill in your values:WEBHOOK_SECRET=your_actual_secret RECEIVED_HASH=sha1hash=<hex_from_x-adsk-signature_header> - Place the raw webhook payload in
sample.jsonat the repo root.
cd python
python verify_signature.py
# Payload: .../sample.json (nnn bytes)
# Received hash: sha1hash=...
# Result: VALID - signature matches the payload.cd javascript
node verifySignature.js
# Payload: .../sample.json (nnn bytes)
# Received hash: sha1hash=...
# Result: VALID - signature matches the payload.cd csharp
dotnet run
# Payload: .../sample.json (nnn bytes)
# Received hash: sha1hash=...
# Result: VALID - signature matches the payload.Each tool also supports a --test flag to run built-in self-tests:
python verify_signature.py --test
node verifySignature.js --test
dotnet run -- --test| Sample | Requirements |
|---|---|
| Python | Python 3.8+ |
| Node.js | Node.js 18+ |
| C# | .NET 8 SDK |
This sample is licensed under the terms of the MIT License. Please see the LICENSE file for full details.
Joao Martins in/jpornelas, Developer Advocate