Secure your backend services' communication with Cloudflare hooks.

Signing

As the endpoint you receive hooks on will be public to the internet, it’s critical you verify that it is in fact Cloudflare Apps making the request before taking action. To do that verification, we send you a signature of the content of the request, signed with a secret token only known to Cloudflare Apps and to you.

After saving your app for the first time you will see the “App Security Key” field appear on your app’s configuration page. Click “Reveal” and store this key securely.

Requests we send will include a header called X-Signature-HMAC-SHA256-HEX which is a hex encoded SHA-256 HMAC of the entire (uncompressed) body of the request. If this header is invalid you must reject it.

We include an additional header called X-Signature-Key-Variant which allows you to test your app in the App Creator, and to rotate keys if required. This value tells you which key we’ve signed the hook with:

X-Signature-Key-VariantKey
test“test-key”
1YOUR SECRET KEY

In other words, use the key test-key if the Key-Variant is “test”, your secret key otherwise. You must not perform any actions on live customer data if the sent Key-Variant is “test.” Anyone can fake these requests in the App Creator or manually.

An easy way to finish your validation is to check if the provided app.id is a value other than “local” or the empty string. If it is, but the Key-Variant was “test”, deny the request. Alternatively you do not need to support the test Key-Variant when you are done developing your app.

Here is an example of how to verify the HMAC in Node.js:


  http.createServer(function (req, res) {
    if (req.headers['x-signature-key-variant'] === 'test'){
      // /!\ DO NOT ACTUALLY MANIPULATE CUSTOMER DATA /!\
      // ...but we can test it in the App Creator.
      var key = 'test-key'
    } else {
      // This is a production request.
      var key = 'MY_SECRET_KEY'
    }

    var hash = crypto.createHmac('sha256', key)

    req.on('data', function (data) {
      hash.update(data)
    })

    req.on('end', function () {
      var hashString = hash.digest('hex')
      if (hashString !== req.headers['x-signature-hmac-sha256-hex'])
        throw new Error('Hook signature does not match')
    })
  })

If you are using Express, you can add your verifier to the bodyParser:


  app.use(bodyParser.json({
    verify: function (req, res, buf, encoding) {
      if (req.headers['x-signature-key-variant'] === "test") {
        // /!\ DO NOT ACTUALLY MANIPULATE CUSTOMER DATA /!\
        // ...but we can test it in the App Creator.
        var key = "test-key"
      } else {
        // This is a production request.
        var key = 'MY_SECRET_KEY'
      }

      var hash = crypto.createHmac('sha256', key)
      hash.update(buf)

      var hashString = hash.digest('hex')
      if (hashString !== req.headers['x-signature-hmac-sha256-hex'])
        throw new Error('Hook signature does not match')
    }
  }));