Twitter 401 Unauthorized -- OAuth Request Token - php

I am using file_get_contents in PHP to make HTTP requests to the Twitter API.
When trying to request a token, I get the error:
Warning: file_get_contents(https://api.twitter.com/oauth/request_token): failed to open stream: HTTP request failed! HTTP/1.0 401 Unauthorized
Here is my code
$appID = "MY-CONSUMER-ID";
$appSecret = "MY-CONSUMER-SECRET";
$url = "https://api.twitter.com/oauth/request_token";
$oauth = array(
"oauth_nonce" => base64_encode(time()),
"oauth_callback" => "MY-URL",
"oauth_signature_method" => "HMAC-SHA1",
"oauth_timestamp" => time(),
"oauth_consumer_key" => $appID,
"oauth_version" => "1.0"
);
$token_string = "POST&" . rawurlencode($url) . "&" . rawurlencode(http_build_query($oauth));
$signing_key = rawurlencode($appSecret) . "&";
$signature = base64_encode(hash_hmac("sha1", $token_string, $signing_key, true));
$oauth["oauth_signature"] = $signature;
$header = array();
foreach ($oauth as $key => $value) { $header[] = rawurlencode($key) . "=\"" . rawurlencode($value) . "\""; }
$header = implode(", ", $header);
$header = "Authorization: OAuth " . $header;
echo $header;
$opts = array('http' => array(
'method' => "POST",
'header' => $header,
) );
$context = stream_context_create($opts);
$result = file_get_contents($url, false, $context);

You actually helped me and I'll help anyone else who reads this post.
The issue why this wasn't working was because the $oauth array must be in alphabetical order (see https://dev.twitter.com/docs/auth/creating-signature). Thus when it is http_build_queried it was wrong.
However this helped me because my signature was passing an expected o_token when we don't at this point have one (I use this code for signing all requests) so $signing_key = rawurlencode($appSecret) . "&"; helped fix my problem.

Related

file_get_contents(): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request

I am getting the error Warning: file_get_contents(https://partner.uat.shopeemobile.com/api/v1/item/categories/get): failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request in C:\xampp\htdocs\addproduct.php on line 43
<?php
$api_authorization_base_url = "https://partner.shopeemobile.com/api/v1/shop/auth_partner";
$redirect_url = "https://www.google.com";
$partner_id = 840565;
$shopid = 209194;
$key = "aca9b2236136e7aeb8be2b11197a181cd6bc672cbc641f8fe41d0850b7b7f63a";
$token_base_string = $key . $redirect_url;
$token = hash('sha256', $token_base_string);
$data = array(
'id' => $partner_id,
'token' => $token,
'redirect' => $redirect_url
);
$api_authorization_url = $api_authorization_base_url . "?" . json_encode($data);
// echo $api_authorization_url . "\n";
$get_order_by_status_url = "https://partner.uat.shopeemobile.com/api/v1/item/categories/get";
$data = array(
'partner_id' => $partner_id,
'shopid' => $shopid,
'timestamp' => time(),
"language" => "en"
);
$sig_base_string = $get_order_by_status_url . " |" . json_encode($data);
$sig = hash_hmac('sha256', $sig_base_string, $key);
$header = [
'Authorization' => $sig
];
$options = array(
'http' => array(
'header' => "Content-type: application/json\r\n Authorization: " . $sig,
'method' => 'POST /api/v1/item/categories/get HTTP/1.1',
'content' => json_encode($data)
),
);
$context = stream_context_create($options);
// print_r($sig_base_string);
$result = file_get_contents($get_order_by_status_url, false, $context);
print_r($result);
?>
In the $options array you have 'method' and you are passing in invalid stuff, method should be just a valid HTTP request method like POST or GET etc.

Acquire youtube reporting access token

I'm trying to follow the Using OAuth 2.0 for Server to Server Applications guide to get an access token so that I can use the Youtube Reporting API.
But no matter what I do, I always this result:
Warning: file_get_contents(https://www.googleapis.com/oauth2/v4/token): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request
Here's my code
$contents = file_get_contents('BCGA-557d334b8526.json');
$account = json_decode($contents, TRUE);
$privateKeyString = $account['private_key'];
$time = time();
$expiration = $time + 3600;
$header = '{"alg":"RS256","typ":"JWT"}';
$claim_set = '{"iss":"youtube-reporting#ataproject-850089.iam.gserviceaccount.com","scope":"https://www.googleapis.com/auth/yt-analytics.readonly","aud":"https://www.googleapis.com/oauth2/v4/token","exp":"' . $expiration . '","iat":"' . $time . '"}';
$unsignedToken = base64_encode($header) . '.' . base64_encode($claim_set);
$signature = hash_hmac('sha256', $unsignedToken, $privateKeyString, true);
$jwt = base64_encode($header) . '.' . base64_encode($claim_set) . '.' . base64_encode($signature);
$url = "https://www.googleapis.com/oauth2/v4/token";
$data = array('grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt);
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
var_dump($result);
Any suggestions?
You forgot
'grant_type' => 'refresh_token'

Post request with file_get_content not working

I am trying to use file_get_contents to "post" to a url and get auth token. The problem I am having is that it returns a error.
Message: file_get_contents(something): failed to open stream: HTTP request failed! HTTP/1.1 411 Length Required.
I am not sure what is causing this but need help. Here is the function.
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$context = stream_context_create(array (
'http' => array (
'header' => 'Authorization: Basic ' . base64_encode("$username:$password"),
'method' => 'POST'
)
));
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
I tried it with POSTMAN, and it works, so only problem I am having is that why isnt it working with file_get_contents.
Cannot command so i will do it this way. If you use Postman why don't you let Postman generate the code for you. In postman you can click code at a request and you can even select in what coding language you wanne have it. Like PHP with cURL:
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "http://somthing.com/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => array(
"password: somthing",
"username: gettoken"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
Hope this will help!
I can not comment because of my reputation;
In some servers file_get_content is not available...
You may try with CURL like this
Your request havent any data and content length is missing.
You can try this:
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$data = array('foo' => 'some data');
$data = http_build_query($data);
$context_options = array (
'http' => array (
'method' => 'POST',
'header'=> "Content-type: application/x-www-form-urlencoded\r\n"
. "Authorization: Basic " . base64_encode("$username:$password") . "\r\n"
. "Content-Length: " . strlen($data) . "\r\n",
'content' => $data
)
);
$context = context_create_stream($context_options);
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
Here is similar problem:
How to fix 411 Length Required error with file_get_contents and the expedia XML API?
RFC2616 10.4.12
https://www.rfc-editor.org/rfc/rfc2616#section-10.4.12
Code: (Doesn't work, see below)
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$context = stream_context_create(array (
'http' => array (
'header' => 'Authorization: Basic ' . base64_encode("$username:$password") . 'Content-Length: ' . strlen($url) . '\r\n',
'method' => 'POST'
)
));
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
2nd Try:
public function ForToken(){
$username = 'gettoken';
$password = 'something';
$url = 'https://something.com';
$context_options = array (
'http' => array (
'method' => 'POST',
'header'=> "Content-type: application/x-www-form-urlencoded\r\n" . "Authorization: Basic " . base64_encode("$username:$password") . "Content-Length: " . strlen($url) . "\r\n",
'content' => $url
)
);
$context = stream_context_create($context_options);
$token = file_get_contents($url, false, $context);
if(token){
var_dump($token);
}else{
return $resultArray['result'] = 'getting token failed';
}
}
This is from patryk-uszynski's answer formatted with the OP's code.

Can not obtain a request token twitter Rest API 1.1

since a week I'm trying to manage "Login with twitter" functionality in my website. I can not complete even the first step: 'obtain a request token'. I recieve:
"Failed to validate oauth signature and token"
I'm doing everything like said here: https://dev.twitter.com/docs/auth/implementing-sign-twitter
And creating a signature like here: https://dev.twitter.com/docs/auth/creating-signature
My code:
date_default_timezone_set('UTC');
$oauth_callback = 'http://mydomain.net'; // calls are made from index.php
$url = 'https://api.twitter.com/oauth/request_token';
$oauth_consumer_key = '***';
$oauth_nonce = str_shuffle(trim(base64_encode(time()), '='));
$oauth_signature_method = 'HMAC-SHA1';
$oauth_timestamp = time();
$oauth_token = '***';
$oauth_version = '1.0';
$HTTPMethod = 'POST';
$BaseURL = 'https://api.twitter.com/oauth/request_token';
$consumer_secret = '***';
$access_token_secret = '***';
$params = array(
'oauth_consumer_key' => $oauth_consumer_key,
'oauth_nonce' => $oauth_nonce,
'oauth_signature_method' => $oauth_signature_method,
'oauth_timestamp' => $oauth_timestamp,
'oauth_token' => $oauth_token,
'oauth_version' => $oauth_version,
'oauth_callback' => $oauth_callback
);
function parameter_string (array $params)
{
$temp_array = array();
$parameter_string = '';
while (current($params)) {
$temp_array[rawurlencode(key($params))] = rawurlencode(current($params));
next($params);
}
ksort($temp_array);
foreach ($temp_array as $key => $value) {
$parameter_string .= '&' . $key . '=' . $value;
}
return trim($parameter_string, '&');
}
$parameter_string = parameter_string($params);
function signature_base_string ( $HTTPMethod, $BaseURL, $parameter_string)
{
$signature_base_string = $HTTPMethod . '&' . rawurlencode($BaseURL) . '&' . rawurlencode($parameter_string);
return $signature_base_string;
}
$signature_base_string = signature_base_string ($HTTPMethod, $BaseURL, $parameter_string);
function signing_key($consumer_secret)
{
return rawurlencode($consumer_secret) . '&';
}
$signing_key = signing_key($consumer_secret);
$oauth_signature = base64_encode(hash_hmac('SHA1', $signature_base_string, $signing_key, true));
$header[] = 'Authorization: OAuth '.
'oauth_callback="'.rawurlencode($oauth_callback).'", '.
'oauth_consumer_key="'.rawurlencode($oauth_consumer_key).'", '.
'oauth_nonce="'.rawurlencode($oauth_nonce).'", '.
'oauth_signature="'.rawurlencode($oauth_signature).'", '.
'oauth_signature_method="'.rawurlencode('HMAC-SHA1').'", '.
'oauth_timestamp="'.rawurlencode($oauth_timestamp).'", '.
'oauth_version="'.rawurlencode('1.0').'"';
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLINFO_HEADER_OUT => true,
CURLOPT_HTTPHEADER => $header,
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true
);
$c = curl_init();
$d = curl_setopt_array($c, $options);
$response = curl_exec($c);
echo '<pre>';
print_r($response);
echo '</pre>';
echo '<pre>';
print_r (curl_getinfo($c));
echo '</pre>';
curl_close($c);
The request header looks like this:
POST /oauth/request_token HTTP/1.1
Host: api.twitter.com
Accept: */*
Authorization: OAuth oauth_callback="http%3A%2F%2Fmydomain.net", oauth_consumer_key="***", oauth_nonce="2DHXEIM541CPONJS3UFRQ79G8W0KA6LYZBT", oauth_signature="***", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1379239417", oauth_version="1.0"
Content-Length: 0
Content-Type: application/x-www-form-urlencoded
Please help!

HTTP request using fopen and curl_setopt

If cURL is unavailable I want to send HTTP requests using fopen. I got the code for a class from a PACKT RESTful PHP book but it does nto work. Any ideas why?
if ($this->with_curl) {
//blah
} else {
$opts = array (
'http' => array (
'method' => "GET",
'header' => array($auth,
"User-Agent: " . RESTClient :: USER_AGENT . "\r\n"),
)
);
$context = stream_context_create($opts);
$fp = fopen($url, 'r', false, $context);
$result = fpassthru($fp);
fclose($fp);
}
return $result;
}
The HTTP context options are laid out here: http://www.php.net/manual/en/context.http.php
The header option is a string, so as #Mob says you should be using \r\n and string concatenation rather than an array. However, user_agent is a valid key, so you could just use that instead.
I'm guessing that the contents of the $auth variable is something along the lines of Authorization: blah - i.e. standard header format?
The below code is a working example. Note that I've changed your fpassthru() (which outputs the content to the browser, and does not store it to $result) to a fread() loop. Alternatively you could have wrapped the fpassthru() call with ob_start(); and $result = ob_get_clean();
<?php
class RESTClient {
const USER_AGENT = 'bob';
}
$url = 'http://www.example.com/';
$username = "fish";
$password = "paste";
$b64 = base64_encode("$username:$password");
$auth = "Authorization: Basic $b64";
$opts = array (
'http' => array (
'method' => "GET",
'header' => $auth,
'user_agent' => RESTClient :: USER_AGENT,
)
);
$context = stream_context_create($opts);
$fp = fopen($url, 'r', false, $context);
$result = "";
while ($str = fread($fp,1024)) {
$result .= $str;
}
fclose($fp);
echo $result;
You're mixing this. Shouldn't it be ::
$opts = array (
'http' => array (
'method' => "GET",
'header' => $auth . "\r\n" . //removed array()
"User-Agent: " . RESTClient :: USER_AGENT . "\r\n" )
)
Here's an example of setting headers from the PHP manual
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en\r\n" .
"Cookie: foo=bar\r\n"
)
);

Categories