Authentication problem when registering webhook

php
webhooks

#1

Hi guys! Im new here :slight_smile:
I am also rather new regarding developing in general.

I’m trying to register a webhook to listen on account activity (my own twitter timeline), but when I run the script register-webhook-script I get the following error:
“{“errors”:[{“code”:32,“message”:“Could not authenticate you.”}]}”

I would greatly appreciate any advice on what might be wrong! Might be I’ve missed something obvious :slight_smile:

Below is the script code. I have put it toghether by following the guidelines in:
https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/guides/getting-started-with-webhooks.html & https://developer.twitter.com/en/docs/basics/authentication/guides/authorizing-a-request.html

<?php
//keys and tokens
$consumer_key='xxx';
$consumer_secret='xxxx';
$access_token='xxxxx';
$access_token_secret='xx';

//generate url
$url = 'https://abc123.com/webhooks/twitter/listen.php'; //url for listening script
$twitter_url = 'https://api.twitter.com/1.1/account_activity/all/test/webhooks.json?url=';
$webhooksurl = $twitter_url;
$webhooksurl.=$url;

//generate nonce
function random_str($length, $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
    $pieces = [];
    $max = mb_strlen($keyspace, '8bit') - 1;
    for ($i = 0; $i < $length; ++$i) {
        $pieces []= $keyspace[random_int(0, $max)];
    }
    return implode('', $pieces);
}
$b64=base64_encode(random_str(30));
$nonce=preg_replace("/[^A-Za-z0-9 ]/", '', $b64); //strip all alfanumeric

//genereate timestamp
$oauth_timestamp=time();

//generate oauth_signature
$ps='';  //parameter string, part of oauth signature string
$ps.=rawurlencode('include_entities');
$ps.='=';
$ps.=rawurlencode('true'); //unsure on this one
$ps.='&';
$ps.=rawurlencode('oauth_consumer_key');
$ps.='=';
$ps.=rawurlencode($consumer_key);
$ps.='&';
$ps.=rawurlencode('oauth_nonce');
$ps.='=';
$ps.=rawurlencode($nonce);
$ps.='&';
$ps.=rawurlencode('oauth_signature_method');
$ps.='=';
$ps.=rawurlencode('HMAC-SHA1');
$ps.='&';
$ps.=rawurlencode('oauth_timestamp');
$ps.='=';
$ps.=rawurlencode($oauth_timestamp);
$ps.='&';
$ps.=rawurlencode('oauth_token');
$ps.='=';
$ps.=rawurlencode($access_token);
$ps.='&';
$ps.=rawurlencode('oauth_version');
$ps.='=';
$ps.=rawurlencode('1.0');
//----- unsure if below should be included since its not a status update. have tried not including it.
$ps.='&';
$ps.=rawurlencode('status');
$ps.='=';
$ps.=rawurlencode('');

//signature_base_string, part of oauth signature string
$sbs='POST';    
$sbs.='&';
$sbs.=rawurlencode($webhooksurl);
$sbs.='&';
$sbs.=rawurlencode($ps);

//signing key, part of oauth signature string
$sk=''; 
$sk.=rawurlencode($consumer_secret);
$sk.='&';
$sk.=rawurlencode($access_token_secret);

$oauth_signature=hash_hmac('sha1',$sbs,$sk,true);
$oauth_signature=base64_encode($oauth_signature); //oauth signature string


//header string
$dst='';
$dst.='OAuth ';
$dst.=rawurlencode('oauth_consumer_key');
$dst.='="';
$dst.=rawurlencode($consumer_key);
$dst.='", ';
$dst.=rawurlencode('oauth_nonce');
$dst.='="';
$dst.=rawurlencode($nonce);
$dst.='", ';
$dst.=rawurlencode('oauth_signature');
$dst.='="';
$dst.=rawurlencode($oauth_signature);
$dst.='", ';
$dst.=rawurlencode('oauth_signature_method');
$dst.='="';
$dst.=rawurlencode('HMAC-SHA1');
$dst.='", ';
$dst.=rawurlencode('oauth_timestamp');
$dst.='="';
$dst.=rawurlencode($oauth_timestamp);
$dst.='", ';
$dst.=rawurlencode('oauth_token');
$dst.='="';
$dst.=rawurlencode($access_token);
$dst.='", ';
$dst.=rawurlencode('oauth_version');
$dst.='="';
$dst.=rawurlencode('1.0');
$dst.='"';

$headers = array(
	'content-type: application/x-www-form-urlencoded',	
	'authorization: '.$dst
);

$ch = curl_init(); 
curl_setopt($ch, CURLOPT_URL, $webhooksurl); 
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); 
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 
$result  = curl_exec($ch); 
curl_close($ch); 

echo '<pre>';print_r($result);exit;
?>

#2

Can you double check your authentication? Are you able to use this authentication to make other calls on your own account, other than registering a webhook?


#4

We also have a troubleshooting guide for this error message and API here:
https://developer.twitter.com/en/docs/accounts-and-users/subscribe-account-activity/FAQ#troubleshooting


#5

Hi! Sorry for my late reply.
I haven’t used this particular script for other purposes, but I have successfully used my twitter keys/tokens in a test script where I read posts on my home_timeline:

//include library
require "twitteroauth/autoload.php";
use Abraham\TwitterOAuth\TwitterOAuth;

//connect to api
$connection=new TwitterOAuth($consumer_key,$consumer_secret,$access_token,$access_token_secret);
$content=$connection->get("account/verify_credentials");
$statuses=$connection->get("statuses/home_timeline",["exclude_replies"=>true]);

… so at least there’s nothing wrong with my tokens.

I suspect the problem might lie somewhere in the header string generation. Maybe in the $ps string. I’m not sure I use correct settings there.

Is there no easy way to do this? For example, I read someone had registered a webhook using the TwitterOAuth library. If someone could point the way how to do something like that I’d be grateful!

Thank you for your time!


#6

Thanks, have looked there to no avail.


#8

We have updated our troubleshooting documentation for error 32. Please read through this again and make sure that you are using both the proper tokens from your Twitter app that you’ve added to your dev environments page, as well as generate the proper oauth nonce , oauth_signature , and oauth_timestamp tokens.