I have been looking into creating a signature on the OAuth site & over SF but however I create my signature I always get the same error, any ideas what I am doing wrong here?
Error: Failed to validate oauth signature and token
I have a working app for the old rest API so I know that my issue is not with my app or server etc
<?php
function Post_Data($url,$data,$header){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,$data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
// Get OAuth Token
$consumer_key = "hidden";
$consumer_secret = "hidden";
$request_url = "http://api.twitter.com/oauth/request_token";
$callback = "http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
$nonce = md5(time());
$timestamp = time();
$data = array(
"oauth_callback" => $callback,
"oauth_consumer_key" => $consumer_key,
"oauth_nonce" => $nonce,
"oauth_signature_method" => "HMAC-SHA1",
"oauth_timestamp" => $timestamp,
"oauth_version" => "1.0"
);
$post_string = '';
foreach($data as $key => $value){
$post_string .= $key.'='.($value).'&';
}
$post_string = rtrim($post_string, '&');
$base_string = 'GET&'.urlencode($request_url).'&'.urlencode($post_string);
$data["oauth_signature"] = base64_encode(hash_hmac('sha1', $base_string, $consumer_secret, true));
$header = array("Expect:");
$content = Post_Data($request_url,$data,$header);
print_r($content);
?>
Maybe you should remove the "oauth_callback" and try again.
This is my code
class Twitter
{
private $CALLBACK_URL = 'http://your_site';
private $REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token';
private $ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token';
private $AUTHORIZE_URL = 'https://api.twitter.com/oauth/authorize';
private $consumer_key = 'your_key';
private $consumer_secret = 'your_secret';
private $access_token = 'your_token'; // oauth_token
private $access_token_secret = 'your_token_secret';
private $token_secret = '';
private $method = 'POST'; // [HEAD, GET, POST]
private $params = array();
public function get_request_token() {
//$this->params['oauth_callback'] = $this->CALLBACK_URL; // Something worng with this "Failed to validate oauth signature and token", God dammit...
$this->params['oauth_consumer_key'] = $this->consumer_key;
$this->params['oauth_nonce'] = md5(uniqid('prefix'));
$this->params['oauth_signature_method'] = 'HMAC-SHA1'; // [HMAC-SHA1, RSA-SHA1, PLAINTEXT]
$this->params['oauth_timestamp'] = time();
$this->params['oauth_version'] = '1.0'; // [1.0, 1.1] *Optional
$this->params['oauth_signature'] = $this->HMAC_SHA1();
$headers = array();
ksort($this->params);
foreach($this->params as $k => $v){
$headers[] = $this->RFC3986($k).'="'.$this->RFC3986($v).'"';
}
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $this->REQUEST_TOKEN_URL);
curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_HTTPHEADER, array('Authorization: OAuth '.implode(', ', $headers)));
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($c); // if(CURLOPT_RETURNTRANSFER == true){ return "Result" or FALSE }else{ return TRUE or FALSE }
curl_close($c);
return $result;
}
private function HMAC_SHA1() {
$text = $this->get_signature_base_string();
$key = $this->RFC3986($this->consumer_secret).'&'.$this->RFC3986($this->token_secret);
if(function_exists('hash_hmac')){
$signature = base64_encode(hash_hmac('sha1', $text, $key, true));
}else{
$blocksize = 64;
$hashfunc = 'sha1';
if(strlen($key) > $blocksize){
$key = pack('H*', $hashfunc($key));
}
$key = str_pad($key, $blocksize, chr(0x00));
$ipad = str_repeat(chr(0x36), $blocksize);
$opad = str_repeat(chr(0x5c), $blocksize);
$hmac = pack('H*', $hashfunc(($key ^ $opad).pack('H*', $hashfunc(($key ^ $ipad).$base_string))));
$signature = base64_encode($hmac);
}
return $signature;
}
private function get_signature_base_string() {
$base = array(
strtoupper($this->method),
$this->RFC3986($this->REQUEST_TOKEN_URL),
$this->RFC3986($this->get_normalized_params())
);
return implode('&', $base);
}
private function RFC3986($str) {
return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($str))));
}
private function get_normalized_params() {
$normalized = array();
ksort($this->params);
foreach($this->params as $k => $v){
if($k != 'oauth_signature'){
$normalized[] = $k.'='.$v;
}
}
return implode('&', $normalized);
}
}
$T = new Twitter();
echo $T->get_request_token();
Could it be your server clock? http://blainegarrett.com/2009/07/14/failed-to-validate-oauth-signature-and-token-on-twitter-oauth-check-your-cloc/
Related
When I run this code, I get a SignatureDoesNotMatch error
The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
<?php
$param = array();
$param['AWSAccessKeyId'] = 'AWSAccessKeyId';
$param['Action'] = 'ListOrders';
$param['MWSAuthToken'] = 'MWSAuthToken';
$param['MarketplaceId'] = 'A21TJRUUN4KGV';
$param['FulfillmentChannel.Channel.1'] = 'MFN';
$param['PaymentMethod.Method.1'] = 'COD';
$param['OrderStatus.Status.1'] = 'Pending';
$param['OrderStatus.Status.2'] = 'PendingAvailability';
$param['SellerId'] = 'AGNFZGZRZBUP1';
$param['SignatureMethod'] = 'HmacSHA256';
$param['SignatureVersion'] = '2';
$param['CreatedAfter'] = "2017-09-01T13:41:49Z";
$param['Timestamp'] = gmdate("Y-m-d\TH:i:s.\\0\\0\\0\\Z", time());
$param['Version'] = '2013-09-01';
$secret = 'secret key';
$url = array();
foreach ($param as $key => $val) {
$val = str_replace("%7E", "~", rawurlencode($val));
$url[] = $key . "=" . $val;
}
sort($url);
$arr = implode('&', $url);
$sign = 'POST' . "\n";
$sign .= 'mws.amazonservices.in' . "\n";
$sign .= '/Orders/2013-09-01' . "\n";
$sign .= $arr;
$signature = hash_hmac("sha256", $sign, $secret, true);
$signature = urlencode(base64_encode($signature));
$link = "https://mws.amazonservices.in/Orders/2013-09-01?";
$link .= $arr;
$link .= "&Signature=" . $signature;
echo($link); //for debugging - you can paste this into a browser and see if it loads.
$ch = curl_init($link);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-type: application/xml'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
echo "<pre>";
print_r($response);
print_r($info);
?>
Your signature calculation seems fine. However, you're calculating a signature based on a "POST", but then you're actually doing a GET. I'd guess that's what's throwing off the signature calculation on the other side.
Im writing a AWS API request to list users on IAM AWS service. And I'm receiving error message.
<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
<Error>
<Type>Sender</Type>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'GET
/
Action=ListUsers&Version=2010-05-08&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIMPILWMPQSH57DNA%2F20160621%2Fus-east-1%2Fiam%2Faws4_request&X-Amz-Date=20160621T142939Z&X-Amz-SignedHeaders=host
host:iam.amazonaws.com
host
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20160621T142939Z
20160621/us-east-1/iam/aws4_request
c47728e278701ccaada8df76488c18449ada2f1b8aab6275a4bc0ada94af3ce2'
</Message>
</Error>
<RequestId>9672bcf2-37bc-11e6-8b2d-6151d0618c53</RequestId>
</ErrorResponse>
As you can see from my code bellow my canonical string is exactly the same like they wrote in error response but for some reason when im calculating hash my hex value is different that they write.
For example in this error response they wrote that hex value should be
`c47728e278701ccaada8df76488c18449ada2f1b8aab6275a4bc0ada94af3ce2`
and when I use functions
$hashedcanon = hash_hmac("sha256", $canonicalrequest, True);in my code im getting
`57fce72007b43c2621712b85e90fd38f0a1f2c7a3e84799fb9f477ed8546f86e`
Here is my code.
<?php
$AWSAccessKeyId = "<myaccesskey>";
$SecretAccessKey = "<mysecretkey>";
$timestamp = date('Ymd',time()).'T'.date('His',time()).'Z';
$date = date('Ymd',time());
$url = 'https://iam.amazonaws.com';
$method = 'GET';
$postfields['Action'] = 'ListUsers';
$postfields['Version'] = '2010-05-08';
$postfields["X-Amz-Algorithm"] = 'AWS4-HMAC-SHA256';
$postfields['X-Amz-Credential'] = $AWSAccessKeyId.'/'.$date.'/us-east-1/iam/aws4_request';
$postfields['X-Amz-Date'] = $timestamp;
$postfields['X-Amz-SignedHeaders'] = 'host';
$canonicalized_query = array();
foreach ($postfields as $param => $value) {
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$canonicalrequest = $method."\n".
"/\n".
$canonicalized_query."\n".
"host:iam.amazonaws.com\n".
"\n".
"host\n".
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
$hashedcanon = hash_hmac("sha256", $canonicalrequest, True);
$string_to_sign = $postfields["X-Amz-Algorithm"]."\n".$timestamp."\n".$date."/us-east-1/iam/aws4_request\n".$hashedcanon;
$signingkey = hash_hmac("sha256",hash_hmac("sha256",hash_hmac("sha256",hash_hmac("sha256","AWS4".$SecretAccessKey,$date),"us-east-1"),"iam"),"aws4_request");
$signature = hash_hmac("sha256", $string_to_sign, $signingkey, True);
$postfields["X-Amz-Signature"] = $signature;
$canonicalized_query = array();
foreach ($postfields as $param => $value) {
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$fullurl = $url.'/?'.$canonicalized_query;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fullurl);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLINFO_HEADER_OUT, true); // enable tracking
$result = curl_exec($ch);
$headerSent = curl_getinfo($ch, CURLINFO_HEADER_OUT );
?>`
So in general I'm assuming I'm calculating wrong hex value of string to sign since my and theirs hex value of canonical string are not the same.
Also is interesting when I copy/paste my canonical string to http://hash.online-convert.com/sha256-generator I'm getting third hex value (not even my or theirs).
If anyone needs more info I'm willing to provide it or if anyone has working code for any API AWS if it can share it so I throw an eye and compare and hope I can find error.
Thanks
$hashedcanon = hash_hmac("sha256", $canonicalrequest, True);
Well, three issues...
hash_hmac() takes the key as the third argument, not a boolean, and
you aren't supposed to be calculating an HMAC digest here, so hash_hmac() isn't what you want, and
you want it in hex, not binary, so don't pass True.
You're looking for just hash().
$hashedcanon = hash("sha256", $canonicalrequest);
Note, I'm not saying hash_hmac() is not needed elsewhere -- just not on this line.
Hi guys I will post now fixed and working code just if someone else needs it.
<?php
$AWSAccessKeyId = "<my access key>";
$SecretAccessKey = "<my secret key>";
$timestamp = date('Ymd',time()).'T'.date('His',time()).'Z';
$date = date('Ymd',time());
$url = 'https://iam.amazonaws.com';
$method = 'GET';
$postfields['Action'] = 'ListUsers';
$postfields['Version'] = '2010-05-08';
$postfields["X-Amz-Algorithm"] = 'AWS4-HMAC-SHA256';
$postfields['X-Amz-Credential'] = $AWSAccessKeyId.'/'.$date.'/us-east-1/iam/aws4_request';
$postfields['X-Amz-Date'] = $timestamp;
$postfields['X-Amz-SignedHeaders'] = 'host';
$canonicalized_query = array();
foreach ($postfields as $param => $value) {
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$canonicalrequest = $method."\n".
"/\n".
$canonicalized_query."\n".
"host:iam.amazonaws.com\n".
"\n".
"host\n".
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
$hasedcanon = hash("sha256",$canonicalrequest, false);
$credentialScope = $date."/us-east-1/iam/aws4_request";
$string_to_sign = "AWS4-HMAC-SHA256\n{$timestamp}\n{$credentialScope}\n{$hasedcanon}";
$dateKey = hash_hmac('sha256',$date,"AWS4{$SecretAccessKey}",true);
$regionKey = hash_hmac('sha256', "us-east-1", $dateKey, true);
$serviceKey = hash_hmac('sha256', "iam", $regionKey, true);
$key = hash_hmac('sha256','aws4_request',$serviceKey,true);
$signature = hash_hmac('sha256', $string_to_sign, $key);
$postfields["X-Amz-Signature"] = $signature;
$canonicalized_query = array();
foreach ($postfields as $param => $value) {
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$fullurl = $url.'/?'.$canonicalized_query;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $fullurl);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLINFO_HEADER_OUT, true); // enable tracking
$xml = curl_exec($ch);
$headerSent = curl_getinfo($ch, CURLINFO_HEADER_OUT );
$doc = simplexml_load_string($xml);
echo '<pre>';
print_r($doc);
echo '</pre>';
?>
I am attempting to get an access token using my PayPal API credentials, here is the code
<?php
class PayPalAPI
{
private $sandbox = true;
private $url;
private $clientid;
private $secret;
private $data;
public function __construct($sbox = true)
{
$this->url['sandbox'] = "https://api.sandbox.paypal.com";
$this->url['live'] = "https://api.paypal.com";
$this->clientid['sandbox'] = "secretsandboxclientid";
$this->clientid['live'] = "secretliveclientid";
$this->secret['sandbox'] = "secretsandboxkey";
$this->secret['live'] = "secretlivekey";
$this->sandbox = $sbox;
if ($this->sandbox == true)
{
$this->url['use'] = $this->url['sandbox'];
$this->clientid['use'] = $this->clientid['sandbox'];
$this->secret['use'] = $this->secret['sandbox'];
}
else
{
$this->url['use'] = $this->url['live'];
$this->clientid['use'] = $this->clientid['live'];
$this->secret['use'] = $this->secret['live'];
}
}
public function getAccessToken()
{
$ch = curl_init($this->url['use'] + "/v1/oauth2/token");
curl_setopt($ch, CURLOPT_ENCODING, "Accept: application/json");
curl_setopt($ch, CURLOPT_ENCODING, "Accept-Language: en_US");
curl_setopt($ch, CURLOPT_USERPWD, $this->clientid['use'] . ":" . $this->secret['use']);
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
}
$api = new PayPalAPI();
$token = $api->getAccessToken();
var_dump($token);
?>
But the response is not as expected, for some reason it is dumping the godaddy "This is the future of something cool"
Here is the link http://xlagmasterx.com/test.php
Why is this returning the page?
I have the following code in one of my classes:
public function build_httpheader ($options = NULL)
{
if (!$this->oauth_token && !$this->oauth_token_secret && !$this->http_method) {
throw new Exception('The oauth_token, oauth_token_secret and the http method must be set');
}
$url = $this->base_uri;
$url_curl = $this->base_uri;
if ($options) {
$this->options = $options;
$url .= '?';
$url_curl .= '?';
$count = count($options);
foreach($options as $key => $value) {
$count = $count--;
if ($count) {
$url .= '&'.$key.'='.$value;
$url_curl .= '&'.$key.'='.rawurlencode($value);
} else {
$url .= $key.'='.$value;
$url_curl .= $key.'='.rawurlencode($value);
}
}
}
$this->url = $url_curl;
/**
* #internal Create a 32 chars unique string to
* use as the nonce value
*/
list($usec, $sec) = explode(" ", microtime());
$usec = str_replace('0.', '', $usec);
$nonce_str = utf8_encode($sec.$usec.'ABCD'.$sec);
$oauth_nonce = md5($nonce_str);
/**
* #internal Create the initial oAuth array
*/
$oauth = array (
'oauth_consumer_key' => $this->consumer_key,
'oauth_nonce' => $this->$oauth_nonce,
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $this->oauth_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0'
);
/**
* #internal generate basic info
*/
$t_oauth = array();
ksort($oauth);
foreach($oauth as $key=>$value){
$t_oauth[] = "$key=" . rawurlencode($value);
}
$base_info = $this->http_method."&" . rawurlencode($url) . '&' . rawurlencode(implode('&', $t_oauth));
$composite_key = rawurlencode($this->consumer_secret) . '&' . rawurlencode($this->oauth_token_secret);
$oauth['oauth_signature'] = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth_string = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value) {
$values[] = "$key=\"" . rawurlencode($value) . "\"";
}
$oauth_string .= implode(', ', $values);
$this->http_headers = array ($oauth_string, 'Expect:');
}
public function tw_curl_api_call ()
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->http_headers);
if ($this->http_method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
}
if ( ($this->http_method != 'POST') && ($this->http_method != 'GET') ) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->http_method);
}
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
$result = json_decode(curl_exec($ch), TRUE);
$info = curl_getinfo($ch);
curl_close($ch);
return array ('result' => $result, 'info' => $info);
}
Another script uses this class as follows:
$options = array ('resources' => 'help,users,search,statuses');
$tw_wrapper->build_httpheader ($options);
$results = $tw_wrapper->tw_curl_api_call ();
I am however getting an error 215 (bad authentication data). Any ideas (I am aware that there are existing PHP oAuth classes and twitter wrappers, but it does not seem as if any of them has completely migrated to the 1.1 API).
Have you had a look at Codebird? It has support for 1.1 and works well for what I've needed. YMWV of course.
A simple example:
Codebird::setConsumerKey('KEY', 'SECRET');
$cb = Codebird::getInstance();
$cb->setToken('AUTH_KEY', 'AUTH_SECRET');
$result = $cb->statuses_userTimeline(array(
'include_rts' => true,
'screen_name' => 'hansnilsson',
));
The following function gives a validation error instead of the token:
failed to validate oAuth signature and token
function request_token()
{
// Set url
$url = $this->site.$this->request_token_path; // http://api.twitter.com/oauth/request_token
// Params to pass to twitter and create signature
$params['oauth_consumer_key'] = $this->consumerKey;
$params['oauth_token'] = '';
$params['oauth_nonce'] = SHA1(time());
$params['oauth_timestamp'] = time();
$params['oauth_signature_method'] = $this->signatureMethod; // HMAC-SHA1;
$params['oauth_version'] = $this->version; // 1.0
ksort($params);
//print "<pre>"; print_r($params); print "</pre>";
// Create Signature
$concatenatedParams = '';
foreach($params as $k => $v){
$concatenatedParams .= "{$k}={$v}&";
}
$concatenatedParams = substr($concatenatedParams,0,-1);
$signatureBaseString = "POST&".urlencode($url)."&".urlencode($concatenatedParams);
$params['oauth_signature'] = base64_encode(hash_hmac('SHA1', $signatureBaseString, $this->secret."&", TRUE));
// Do cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLINFO_HEADER_OUT, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION,1);
$exec = curl_exec ($ch);
$info = curl_getinfo($ch);
curl_close ($ch);
print $exec;
//print "<pre>"; print_r($info); print "</pre>";
}
Below is what Ive put together so far and it works :-)
class Twitauth
{
var $key = '';
var $secret = '';
var $request_token = "https://twitter.com/oauth/request_token";
function Twitauth($config)
{
$this->key = $config['key']; // consumer key from twitter
$this->secret = $config['secret']; // secret from twitter
}
function getRequestToken()
{
// Default params
$params = array(
"oauth_version" => "1.0",
"oauth_nonce" => time(),
"oauth_timestamp" => time(),
"oauth_consumer_key" => $this->key,
"oauth_signature_method" => "HMAC-SHA1"
);
// BUILD SIGNATURE
// encode params keys, values, join and then sort.
$keys = $this->_urlencode_rfc3986(array_keys($params));
$values = $this->_urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
uksort($params, 'strcmp');
// convert params to string
foreach ($params as $k => $v) {$pairs[] = $this->_urlencode_rfc3986($k).'='.$this->_urlencode_rfc3986($v);}
$concatenatedParams = implode('&', $pairs);
// form base string (first key)
$baseString= "GET&".$this->_urlencode_rfc3986($this->request_token)."&".$this->_urlencode_rfc3986($concatenatedParams);
// form secret (second key)
$secret = $this->_urlencode_rfc3986($this->secret)."&";
// make signature and append to params
$params['oauth_signature'] = $this->_urlencode_rfc3986(base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE)));
// BUILD URL
// Resort
uksort($params, 'strcmp');
// convert params to string
foreach ($params as $k => $v) {$urlPairs[] = $k."=".$v;}
$concatenatedUrlParams = implode('&', $urlPairs);
// form url
$url = $this->request_token."?".$concatenatedUrlParams;
// Send to cURL
print $this->_http($url);
}
function _http($url, $post_data = null)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
if(isset($post_data))
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
$response = curl_exec($ch);
$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->last_api_call = $url;
curl_close($ch);
return $response;
}
function _urlencode_rfc3986($input)
{
if (is_array($input)) {
return array_map(array('Twitauth', '_urlencode_rfc3986'), $input);
}
else if (is_scalar($input)) {
return str_replace('+',' ',str_replace('%7E', '~', rawurlencode($input)));
}
else{
return '';
}
}
}
not sure if your still looking into this, or if it will work for you, but i had a similar setup and had the same issue. I eventually found i was urlencoding one to many times.
Try commenting out this section:
$keys = $this->_urlencode_rfc3986(array_keys($params));
$values = $this->_urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
Worked for me, so maybe it will help.
I'll admit this isn't really an answer, but if you can, use the PECL OAuth package. Rasmus Lerdorf wrote a tutorial on how to use it and it got me around this same issue.
I faced same issue, what I was missing is passing header in to the curl request. As shown in this question, I was also sending the $header = array('Expect:'), which was the problem in my case. I started sending signature in header with other data as below and it solved the case for me.
$header = calculateHeader($parameters, 'https://api.twitter.com/oauth/request_token');
function calculateHeader(array $parameters, $url)
{
// redefine
$url = (string) $url;
// divide into parts
$parts = parse_url($url);
// init var
$chunks = array();
// process queries
foreach($parameters as $key => $value) $chunks[] = str_replace('%25', '%', urlencode_rfc3986($key) . '="' . urlencode_rfc3986($value) . '"');
// build return
$return = 'Authorization: OAuth realm="' . $parts['scheme'] . '://' . $parts['host'] . $parts['path'] . '", ';
$return .= implode(',', $chunks);
// prepend name and OAuth part
return $return;
}
function urlencode_rfc3986($value)
{
if(is_array($value)) return array_map('urlencode_rfc3986', $value);
else
{
$search = array('+', ' ', '%7E', '%');
$replace = array('%20', '%20', '~', '%25');
return str_replace($search, $replace, urlencode($value));
}
}