Securing Webhooks: Verifying Signatures in Different Technologies

Storyblok is the first headless CMS that works for developers & marketers alike.

Webhooks enable real-time communication between applications, but they must be secured to prevent unauthorized access. Storyblok sends a webhook-signature header with each webhook request, which can be verified using a shared secret key (webhook secret) configured when setting up the webhook.

Setting Up a Webhook in Storyblok

Before implementing signature verification, ensure you have created a webhook in Storyblok. Learn more in our webhooks documentation.

learn:

Many JavaScript frameworks automatically parse incoming JSON data, but Storyblok sends webhook payloads as raw text. To avoid issues, ensure your framework processes the payload without automatic JSON parsing. Check its documentation for accessing raw request bodies and use middleware or built-in methods to handle raw payloads properly.

Verifying Webhook Signatures in Different Technologies

Verfify webhook signature - Nodejs + Express
        
      import express from 'express'
import { createHmac } from 'node:crypto'

const app = express()
const port = 4000

//Adding a new property in the request called rawBody with unparsed data
app.use(function (req, res, next) {
  req.rawBody = ''
  req.setEncoding('utf8')
  req.on('data', function (chunk) {
    req.rawBody += chunk
  })
  req.on('end', function () {
    next()
  })
})

//If you are using something like body parser for your project use it here

app.get('/', (req, res) => {
  res.send('Hello World!')
})
app.post('/', async (req, res) => {
  const payload = req.rawBody
  const signature = req.headers['webhook-signature']
  const webhookSecret = 'hello' //What you used in Storyblok
  const generatedSignature = createHmac('sha1', webhookSecret)
    .update(payload)
    .digest('hex')
  const isValid = generatedSignature === signature
  if (isValid) {
    //you logic goes here
  }
  res.json({ isValid, generatedSignature, signature, payload })
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})
    
learn:

If you encounter issues with webhook verification, check the webhook logs in your Storyblok settings to view request details, including payloads and headers. You can also use external tools like webhook.site or RequestBin to inspect webhook requests in real-time for easier debugging.

Implementing signature verification ensures that only valid requests from Storyblok are processed, enhancing security and preventing unauthorized data access.

Author

Dipankar Maikap

Dipankar Maikap

Dipankar is a seasoned Developer Relations Engineer at Storyblok, with a specialization in frontend development. His expertise spans across various JavaScript frameworks such as Astro, Next.js, and Remix. Passionate about web development and JavaScript, he remains at the forefront of the ever-evolving tech landscape, continually exploring new technologies and sharing insights with the community.