Webhook: Compute the hash property

I’m a little confused by this:

If a secret was provided when you created the subscription, Twitch signs the notification payload using that secret. We strongly recommend you verify the signature to confirm that the notification is genuine.

To verify payloads, you need to compute the hash properly. A common reason this may fail is unexpected string manipulation (e.g., JSON encoding or character escaping), which is done automatically by some web frameworks. To debug this, verify that the value of the content-length header matches the number of bytes you received in the notification payload. You may discover that notification hashing for payloads is failing due to unusual Unicode.

Using node, how exactly would I do this? What does the api sign the signature with? sha256?

Assuming express, we can throw a little bodyParser middleware at it

var express = require('express');
var bodyParser = require('body-parser');

var app = 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], mysecret)
                .update(buf)
                .digest('hex');
            req.twitch_signature = xHub[1];
        }
    }
}));
app.route('/webhook/').post(function(req, res) {
    res.send('OK');
    if (req.twitch_hub && req.twitch_hex == req.twitch_signature) {
        // it's good
    } else {
        // it's bad
    }
})

Additional example/previous forum post on the same subject:

See https://www.w3.org/TR/websub/#signing-content

Thanks, however it seems my subscriptions aren’t getting approved even tho I respond to the get request with the “hub.challenge” and challenge token in the 200 reply.

You having a similar issue to

You should only echo the “hub.challenge” with a HTTP 200.

Not two things, as you seem to suggest.

For example:

app.route('/webhook/')
    .get(function(req, res) {
        // challenge

        if (req.query['hub.challenge']) {
            console.log('TwitchWebhooks: Send back the challenge');
            res.send(req.query['hub.challenge']);
       }
   });

Thanks, that’s pretty much what I’m doing. I’m going to see if changing the content type to text/html will solve the issue.

my handler works similar to this:

if (req.query && req.query["hub.challenge"]) {
//extract the properties and alias them.
 const { "hub.challenge": challenge, "hub.topic": topic } = req.query;
 const streamerId = topic.substr(topic.indexOf("=")+1, topic.length-1);
//check and make sure the record exists in my database using the user_id;
 doStuff();
//send back a response if If the record exists.
 return reply.code(200).send({ "hub.challenge": challenge });

At a glance it looks like you’re replying with a javascript object. The only thing in the body of your response should be the challenge string.

Yea, I corrected that.

Odd enough, it seems my subs are being registered, however on stream up and down events a post request doesn’t get fired off to my back end from twitch.

{"total":3,"data":[{"topic":"https://api.twitch.tv/helix/streams?user_id=174955366","callback":"http://<local>:1337/api/media/streams/webhook/update/174955366","expires_at":"2018-09-05T18:45:02Z"},{"topic":"https://api.twitch.tv/helix/streams?user_id=44102296","callback":"http://<local>:1337/api/media/streams/webhook/update/44102296","expires_at":"2018-09-06T00:51:45Z"},{"topic":"https://api.twitch.tv/helix/streams?user_id=19571641","callback":"http://<local>:1337/api/media/streams/webhook/update/19571641","expires_at":"2018-09-06T01:22:07Z"}],"pagination":{}}

I’m using ubuntu on a VM with port forwarding so the twitch api can send/receive requests.

Check your logs to see if you got any data inbound to you.

It’s likely something weird with your setup.

I hope <local> doesn’t mean 127.0.0.1 or something, but then you should be able to get a hook working using localhost/127…

local is just a placeholder for my actual ip address. It actually seems to work.

Hey @Hurt_Box, you’re receiving notifications now? The stream up/down events have an added latency to them (due to consistency requirements of some internal services that should be resolved very soon), so you might need to wait around a few minutes for the events to appear.

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