Twitch WebHook hub.secret verification

Hey All!,

Been doing pretty well moving forward with getting subs to work for the streams endpoint. Got my posts working + twitch get and challenge. Everything is working good. Except… I ran into a snag where I am hitting a miss match in the HMAC calculation in NodeJS in some cases.

Looking at the content-length header vs the req.body I am getting there is a difference in bytes. For a proof test a streamer adds “&” to the stream title and this breaks if they remove it my hub.secret verification works. So I am betting this is a unicode/encoding something issue I am just lost for figuring it out. Has anyone else seen this happen in NodeJs? I am using an Express app + Body.parser so I am poking there to see if there is any weird parsing being done for special chars?

Thanks!

My knowledge of the issue isn’t too in depth, but it seems the cause of the issue is how escaping special characters is encoded. A lot of what I know about the issue is thanks to @BarryCarlyon on the TwitchDev webhooks channel.

I was lucky enough that my way to handle it has worked fine before I even know about the issue, regardless of special characters used, it just happened to be the way I learned how to deal with verification when I started trying out webhooks. If anyone has a better way feel free to share but this is how I do it with Express and bodyParser.

const verify = (req, res, buf, encoding) => {
    const expected = req.headers['x-hub-signature'];
    const calculated = 'sha256=' + crypto.createHmac('sha256', YOUR_SECRET).update(buf).digest('hex');

    req.verified = expected === calculated;
};

app.use(bodyParser.json({ verify: verify }));
1 Like

@Dist thanks for the reply! I will take a look at the way you are handling it as it is a bit different to the way I am.

So yep that worked! I ended up doing something like

router.post(’/routehere’, bodyparser.json({verify: verify}), (req, res, next) => {
//code here
}

where verify is pretty much the same as you provided. Thanks again!

No problem, I’m glad you’ve got it working :slight_smile:

To throw another example solution at it:

const crypto = require('crypto')
var secret = 'WIBBLEWOBBLE';

const bodyParser = require('body-parser');
// http://stackoverflow.com/questions/18710225/node-js-get-raw-request-body-using-express
app.use(bodyParser.json({
    verify: function(req, res, buf, encoding) {
        // is there a hub to verify against
        req.twitch_hub = false;
        if (req.headers && req.headers['x-hub-signature']) {
            req.twitch_hub = true;

            var xHub = req.headers['x-hub-signature'].split('=');

            req.twitch_hex = crypto.createHmac(xHub[0], secret)
                .update(buf)
                .digest('hex');
            req.twitch_signature = xHub[1];
        }
    }
}));

app.post('/webhook/', function(req, res) {
    console.log('Incoming POST for');
    if (req.twitch_hub && req.twitch_hex === req.twitch_signature) {
        res.send('OK');
        // do something with req.body which is an object
    } else {
        // WHY YOU POSTING WILLIS?
        res.send('Pisseth off');// nier
    }
});

Bit more error/checking toleratant if “not twitch” starts POSTing at you.

Yeah that’s pretty much how I do it, since I add req.verified to the webhook requests, in the POST handler I simply check req.verified and if it’s false, log it and res.end() it, otherwise pass the data on to whichever function deals with whatever topic it is.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.