# How to verify a DunSocial webhook signature > Recompute HMAC-SHA256 of the string timestamp.rawBody with your endpoint secret, compare the hex digest to the value after v1= in X-DunSocial-Signature, & reject stale timestamps. Always use the raw request body, never re-serialised JSON. Updated: 2026-10-05. ## Why verify Anyone who learns your webhook URL can send it fake events. The signature proves a request really came from DunSocial & wasn't altered. Skipping verification means trusting whoever posts to that URL. ## The headers Every delivery carries four headers: | Header | Value | |--------|-------| | `X-DunSocial-Signature` | `v1=` followed by a hex HMAC-SHA256 | | `X-DunSocial-Timestamp` | Unix seconds used in the signed string | | `X-DunSocial-Event-Id` | A stable id for the event | | `X-DunSocial-Delivery-Id` | The id of this delivery attempt | ## The check, step by step 1. Read the raw request body as a string 2. Build the signed string: the timestamp, a dot, then the raw body 3. Compute HMAC-SHA256 of it with your endpoint secret 4. Hex-encode the result & compare it to the value after `v1=` 5. Reject if it doesn't match, or if the timestamp is too far from your clock ## Use the raw body This is where most implementations fail. If your framework parses the JSON & you re-serialise it, the bytes can change & the signature won't match. Read the body as text first, verify, then parse. ## A Node example ```ts import { createHmac, timingSafeEqual } from 'node:crypto'; export function verify(rawBody: string, headers: Headers, secret: string) { const timestamp = headers.get('X-DunSocial-Timestamp') ?? ''; const signature = (headers.get('X-DunSocial-Signature') ?? '').replace('v1=', ''); const age = Math.abs(Date.now() / 1000 - Number(timestamp)); if (!timestamp || age > 300) return false; const expected = createHmac('sha256', secret) .update(`${timestamp}.${rawBody}`) .digest('hex'); const a = Buffer.from(expected); const b = Buffer.from(signature); return a.length === b.length && timingSafeEqual(a, b); } ``` Use a constant-time comparison, as above, so timing doesn't leak how much of the signature matched. ## The replay window Rejecting old timestamps stops an attacker replaying a captured request. The DunSocial SDK uses a default window of 300 seconds, which is a sensible choice to copy. Make sure your server's clock is accurate, or valid events will look stale. ## Or let the SDK do it The TypeScript SDK has a helper that does all of this for you & returns the parsed event: ```ts const event = await DunSocial.webhooks.constructEvent( rawBody, { signature, timestamp }, process.env.DUN_WEBHOOK_SECRET! ); ``` DunSocial's SDK verifies deliveries only. Creating endpoints still needs a session, as described in the setup article. ## Deduplicate Use `X-DunSocial-Event-Id` to ignore an event you've already handled. A retried delivery carries the same event id, so storing recent ids makes your handler safe to run twice. ## Related guides - [How to set up a DunSocial webhook endpoint](https://www.dunsocial.com/hub/dunsocial-api-and-sdk-guides/how-to-set-up-a-dunsocial-webhook-endpoint.md) - [How to use the DunSocial TypeScript SDK](https://www.dunsocial.com/hub/dunsocial-api-and-sdk-guides/how-to-use-the-dunsocial-typescript-sdk.md) - [What are webhooks for social media posting?](https://www.dunsocial.com/hub/social-media-automation-for-developers/what-are-webhooks-for-social-media-posting.md) - [What is a personal access token & how does it secure API access?](https://www.dunsocial.com/hub/social-media-automation-for-developers/what-is-a-personal-access-token-and-how-does-it-secure-api-access.md) ## About this document This is the Markdown representation of https://www.dunsocial.com/hub/dunsocial-api-and-sdk-guides/how-to-verify-a-dunsocial-webhook-signature. The HTML version of the same page is at the same URL. You can also request Markdown from any page by sending `Accept: text/markdown`. Machine-readable summary of the whole site: https://www.dunsocial.com/llms.txt ## Company - Product: DunSocial, https://www.dunsocial.com - Legal entity: THISUX PRIVATE LIMITED, Chennai, Tamil Nadu, India - Support: support@dunsocial.com - Open the app: https://app.dunsocial.com/login