Extracting raw body data in Azure Functions (JavaScript) for Twitch EventSub HMAC validation

I’m stuck trying to validate Twitch EventSub requests in my Azure Function (JavaScript v4). The main issue is getting the raw body data to create a matching HMAC signature.

I’ve tried these methods:

  • request.text()
  • request.json() then stringify
  • request.arrayBuffer() and processing the stream
  • request.blob()
  • Adding await request.text() directly to the hmac update

But none of them work. Here’s a snippet of my code:

app.http('twitchEventHandler', {
  methods: ['GET', 'POST'],
  authLevel: 'anonymous',
  handler: async (request, context) => {
    const twitchSignature = request.headers.get('Twitch-Eventsub-Message-Signature');
    const eventTimestamp = request.headers.get('Twitch-Eventsub-Message-Timestamp').toLowerCase();
    const eventId = request.headers.get('Twitch-Eventsub-Message-Id').toLowerCase();
    const eventType = request.headers.get('Twitch-Eventsub-Message-Type').toLowerCase();
    const rawContent = await request.text();  

    const signaturePayload = eventId + eventTimestamp + rawContent;
    const calculatedHmac = 'sha256=' + (crypto.createHmac('sha256', process.env.TWITCH_SECRET).update(signaturePayload).digest('hex'));

    const isSignatureValid = crypto.timingSafeEqual(Buffer.from(calculatedHmac), Buffer.from(twitchSignature));

    if (isSignatureValid) {
      return { status: 200, body: rawContent.challenge, headers: { 'Content-Type': 'text/plain' } };
    } else {
      return { status: 401 };
    }
  }
});

Can anyone help me figure out how to get the correct raw body for HMAC validation in Azure Functions v4?

hey claire, i had similar probs. try using the streamToBuffer function from @azure/functions. it’s built-in and works great:

const rawBody = await streamToBuffer(request.body);
const signaturePayload = eventId + eventTimestamp + rawBody.toString();

this should give u the exact body data for hmac validation. lmk if it helps!

I’ve dealt with this exact problem in my Azure Functions projects. What finally worked for me was using the readableStreamToString function from the @azure/functions package. Here’s the approach:

  1. Import the function at the top of your file:
import { readableStreamToString } from '@azure/functions';
  1. In your handler, replace the rawContent line with:
const rawContent = await readableStreamToString(request.body);

This method preserves the original byte representation of the body, which is crucial for HMAC validation with Twitch EventSub.

Ensure your signaturePayload is constructed as follows:

const signaturePayload = eventId + eventTimestamp + rawContent;

This approach should solve your validation issues. It’s been reliable in my experience, even with complex payloads. Let me know if you need any clarification on implementing this solution.

I’ve encountered similar issues with HMAC validation in Azure Functions. One approach that worked for me was using the getRawBody function from the raw-body package. Here’s how you can modify your code:

  1. Install the package: npm install raw-body
  2. Import it at the top of your file: const getRawBody = require('raw-body')
  3. Replace your rawContent line with:
const rawContent = await getRawBody(request.body);

This should give you the raw body as a Buffer, which you can then use directly in your HMAC calculation. Make sure to adjust your signaturePayload construction accordingly:

const signaturePayload = eventId + eventTimestamp + rawContent.toString('utf8');

This method preserves the exact byte representation of the body, which is crucial for accurate HMAC validation. Give it a try and let me know if it resolves your issue.