# Securing Webhooks To ensure the authenticity of event requests, Mailgun signs them and posts the signature alongside the webhook's event-data. A signature takes the following form: ```JSON { "token": "e0b5477167110d68991efc6b9f89f0a11066af27834600e123", "timestamp": "1770920772", "signature": "12d99f5a15355c180971bed7494d578b093c958f57766f3fe750761baed12345" } ``` | **Parameter** | **Type** | **Description** | | --- | --- | --- | | token | string | Randomly generated string with length of 50. | | timestamp | int | Number of seconds passed since January 1, 1970. | | signature | string | String with hexadecimal digits generated by an HMAC algorithm | To verify the webhook originated from Mailgun, you will need to: - Concatenate timestamp and token values together with no separator. - Encode the resulting string with the HMAC algorithm, using your Webhook Signing Key as a key and SHA256 digest mode. - Compare the resulting hexdigest to the signature. If they do not match then the webhook is not from Mailgun! - Optionally, you can cache the token value locally and not honor any subsequent request with the same token. This will prevent replay attacks. - Optionally, you can check if the timestamp is not too far from the current time. - There can be delays in webhook processing that are outside of Mailgun's control so you don't want to be too aggressive with this check. To visualize, here's a sample NodeJS snippet that checks the Webhook signature: ```javascript const crypto = require('crypto') const verify = ({ signingKey, timestamp, token, signature }) => { const encodedToken = crypto .createHmac('sha256', signingKey) .update(timestamp.concat(token)) .digest('hex') return (encodedToken === signature) } ``` #### TLS Client Authentication If your receiving server uses valid TLS configuration - Mailgun includes a TLS client certificate with our Webhook requests. This allows customers to use transport-level validation by inspecting the TLS certificate provided in the request to perform additional validation for whether the request originated from Mailgun. How it works: - Mailgun includes our TLS client certificate in webhook requests, which is owned and managed by Mailgun and is issued by DigiCert - Your server should be configured to only accept requests from clients with valid TLS certificates issued by a trusted CA (e.g., DigiCert) - Once you've confirmed the certificate is valid: then verify that the certificate's Common Name (CN) is `webhooks.mgsend.net` Warning! We do not support validation of server certificates issued by custom CA’s on Mailgun's side before sending, i.e mutual TLS (mTLS) You can download the current certificate for inspection from our [US](https://api.mailgun.net/v1/webhooks/tls_cert) or [EU](https://api.eu.mailgun.net/v1/webhooks/tls_cert) API.