HMAC (Hash-based Message Authentication Code) is a method used to authenticate a message using a shared secret and a hash function. It allows our clients to verify that the received webhook is from a trusted source (Deck) and that the information wasn’t tampered with, in which case the signature won’t match the shared secret. We use SHA-256, so trying to verify the hash with anything else will not work.
An HMAC key is generated automatically when creating an account. To access it, go to your Dashboard and click on “API Keys” from the left menu. Click on “Security” and you will see your HMAC Key on top.The HMAC Key is the same for both Live and Sandbox environments.
Any Webhook that will be sent to you will include an X-Signature header containing the HMAC hash of the payload. This signature can be validated using the aforementioned HMAC key.
The HMAC is in Base64.Note that Base64 is used to encode the raw binary output of the HMAC hash into a text-safe string so it can be sent via HTTP headers or stored easily. HMAC is not used to encrypt the rest of the information passed through the webhook, but its presence does not affect the encryption already in place.
To verify that the HMAC received matches the one for your Team, you can use the following code examples.
Copy
Ask AI
const crypto = require("crypto");// Provided Base64-encoded secretconst secretBase64 = <<YOUR_DECK_WEBHOOK_SECRET_FROM_DASHBOARD>>;// JSON body payload as a raw string (must match byte-for-byte) - This is AN EXAMPLE Webhook Event Bodyconst body = `{"link_token":"link-sandbox-77bd1897-b21b-4eb8-fca6-08dda362f7ed","public_token":"public-sandbox-b7500d0c-920d-46cf-44eb-08dda3634c66","webhook_type":"Link","webhook_code":"ConnectionCreated","environment":"Sandbox"}`;// Decode the Base64 secret into a raw byte bufferconst key = Buffer.from(secretBase64, "base64");// Create the HMAC hashconst hmac = crypto.createHmac("sha256", key);hmac.update(body);const computedSignature = hmac.digest("base64");// Outputconsole.log("Expected Signature:", <<X_SIGNATURE_FROM_HEADER>>);console.log("Computed Signature:", computedSignature);
Make sure that the Expected Signature and Computed Signature match.