Hello, I have a somewhat complex problem. I’m trying to use the webhooks for channel points. The part to register the webhook works, the problem is in the callback part.
My problem is that I have a server in nodejs for the twitch bot and a server with apache2 and ssl to receive and send the verification, I leave the php code which I did to “send the verification”, I also leave the code that I use for " generate the webhook".
The problem is that it tells me “webhook_callback_verification_failed”, which I don’t know where the problem is because it doesn’t give me much info.
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
// Notification request headers
$TWITCH_MESSAGE_ID = 'Twitch-Eventsub-Message-Id';
$TWITCH_MESSAGE_TIMESTAMP = 'Twitch-Eventsub-Message-Timestamp';
$TWITCH_MESSAGE_SIGNATURE = 'Twitch-Eventsub-Message-Signature';
$MESSAGE_TYPE = 'Twitch-Eventsub-Message-Type';
// Notification message types
$MESSAGE_TYPE_VERIFICATION = 'webhook_callback_verification';
$MESSAGE_TYPE_NOTIFICATION = 'notification';
$MESSAGE_TYPE_REVOCATION = 'revocation';
// Prepend this string to the HMAC that's created from the message
$HMAC_PREFIX = 'sha256=';
// Get the raw request body
$body = file_get_contents('php://input');
// Get the headers
$headers = array();
foreach ($_SERVER as $key => $value) {
if (substr($key, 0, 5) === 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($key, 5)))))] = $value;
}
}
// Get the secret
$secret = "aklsgfjhkalosghalshgaklsfjlasf";
// Build the message used to get the HMAC.
$message = $headers[$TWITCH_MESSAGE_ID] .
$headers[$TWITCH_MESSAGE_TIMESTAMP] .
$body;
// Get the HMAC.
$hmac = $HMAC_PREFIX . hash_hmac('sha256', $message, $secret);
// Verify whether our hash matches the hash that Twitch passed in the header.
if (hash_equals($hmac, $headers[$TWITCH_MESSAGE_SIGNATURE])) {
// Signatures match
if ($headers[$MESSAGE_TYPE] === $MESSAGE_TYPE_NOTIFICATION) {
// TODO: Do something with the event's data.
$notification = json_decode($body, true);
// Log the notification to a file
$log = sprintf("[%s] %s\n", date('Y-m-d H:i:s'), json_encode($notification, JSON_PRETTY_PRINT));
file_put_contents('file.log', $log, FILE_APPEND);
// Forward the notification to another link
$ch = curl_init('http://192.168.1.40:3181/channel_points');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_exec($ch);
curl_close($ch);
http_response_code(204);
} else if ($headers[$MESSAGE_TYPE] === $MESSAGE_TYPE_VERIFICATION) {
http_response_code(200);
echo $notification['challenge'];
} else if ($headers[$MESSAGE_TYPE] === $MESSAGE_TYPE_REVOCATION) {
// TODO: Handle revocation
http_response_code(204);
} else {
http_response_code(204);
}
} else {
// Signatures didn't match
http_response_code(403);
}
AND here its code for makesub with nodejs , i use express for join link and tests.
app.get("/makesub", function (req, res) {
axios
.post(
"https://id.twitch.tv/oauth2/token",
`client_id=${idcliente}&client_secret=${secretclient}&grant_type=client_credentials`,
{ headers: { "Content-Type": "application/x-www-form-urlencoded" } }
)
.then((response) => {
var app_access_token = response.data.access_token;
var app_expires_in = response.data.expires_in;
var app_token_type = response.data.token_type;
var postData = {
type: "channel.channel_points_custom_reward_redemption.add",
version: "1",
condition: {
broadcaster_user_id: broadcaster_id,
},
transport: {
method: "webhook",
callback: "https://xxxxxxx/tw.php",
secret: "aklsgfjhkalosghalshgaklsfjlasf",
},
};
let axiosConfig = {
headers: {
"Client-ID": idcliente,
Authorization: `Bearer ${app_access_token}`,
"Content-Type": "application/json",
},
};
axios
.post(
"https://api.twitch.tv/helix/eventsub/subscriptions",
postData,
axiosConfig
)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
res.sendStatus(200);
});