I use Php for twitter autorization (OAuth). Can not get user email in response.
define('ACCOUNT_EMAIL','https://api.twitter.com/1.1/account/verify_credentials.json');
$oauth_nonce = md5(uniqid(rand(), true));
$oauth_timestamp = time();
$oauth_token = $response['oauth_token'];
$oauth_token_secret = $response['oauth_token_secret'];
$screen_name = $response['screen_name'];
//create oauth signature
$params = array(
'oauth_consumer_key=' . CONSUMER_KEY . URL_SEPARATOR,
'oauth_nonce=' . $oauth_nonce . URL_SEPARATOR,
'oauth_signature_method=HMAC-SHA1' . URL_SEPARATOR,
'oauth_timestamp=' . $oauth_timestamp . URL_SEPARATOR,
'oauth_token=' . $oauth_token . URL_SEPARATOR,
'oauth_version=1.0' . URL_SEPARATOR,
'screen_name=' . $screen_name,
//'include_email=true'
);
$oauth_base_text = 'GET' . URL_SEPARATOR . urlencode(ACCOUNT_EMAIL) . URL_SEPARATOR . implode('', array_map('urlencode', $params));
$key = CONSUMER_SECRET . '&' . $oauth_token_secret;
$signature = base64_encode(hash_hmac("sha1", $oauth_base_text, $key, true));
// get userinfo
$params = array(
'oauth_consumer_key=' . CONSUMER_KEY,
'oauth_nonce=' . $oauth_nonce,
'oauth_signature=' . urlencode($signature),
'oauth_signature_method=HMAC-SHA1',
'oauth_timestamp=' . $oauth_timestamp,
'oauth_token=' . urlencode($oauth_token),
'oauth_version=1.0',
'screen_name=' . $screen_name,
//'include_email=true'
);
$url = ACCOUNT_EMAIL . '?' . implode(URL_SEPARATOR, $params);
$response = file_get_contents($url);
print_r($response);
When **include_email=true is open - i get nothing.
When include_email=true is block - i get all userinfo (without email).**
In my admin profile I set Request email addresses from users and send info for special permission in twitter support.
Regenerate keys too.
What is problem in it&
Add cURL
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_HEADER, TRUE);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($curl);
curl_close($curl);
print_r($result);
1 way
url = https://api.twitter.com/1.1/account/verify_credentials.json?oauth_consumer_key=XXXXXXXX&oauth_nonce=XXXXXX&oauth_signature=XXXXX&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1509963372&oauth_token=XXXXXX&oauth_version=1.0&screen_name=ssds
result = HTTP/1.1 200 OK + all field without email
2 way
url = https://api.twitter.com/1.1/account/verify_credentials.json?oauth_consumer_key=XXXXXXXX&oauth_nonce=XXXXXX&oauth_signature=XXXXX&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1509963372&oauth_token=XXXXXX&oauth_version=1.0&screen_name=ssds&include_email=true
result = HTTP/1.1 401 Authorization Required + {"errors":[{"code":32,"message":"Could not authenticate you."}]}
2 way with email not work.
I solved this problem and get email!
This is view of last url
define('ACCOUNT_EMAIL','https://api.twitter.com/1.1/account/verify_credentials.json');
curl_setopt($curl, CURLOPT_URL, ACCOUNT_EMAIL . '?include_email=true&screen_name='.$screen_name);
Related
I want to use an endpoint that uses an url parameter with spaces in it.
I have a function that generates an signature.
function generateSignature($request, $timestamp, $nonce)
{
Global $consumerKey, $accessToken, $consumerSecret, $tokenSecret, $realm, $signatureMethod, $version, $limit;
$baseparams = "";
$baseurl = strtok($request['url'], "?");
$base = strtoupper($request['method']) . "&" . urlencode($baseurl) . "&";
if(strpos($request['url'], '?') !== false){
$url_components = parse_url($request['url']);
parse_str($url_components['query'], $params);
$paramnr = 0;
foreach($params as $param => $value){
$paramnr++;
if($paramnr > 1){
$baseparams .= "&".$param."=" . urlencode($value);
}
else{
$baseparams .= $param."=" . urlencode($value);
}
}
$trailingand = "&";
}
else{
$trailingand = "";
}
echo $baseparams .= $trailingand
. "oauth_consumer_key=" . urlencode($consumerKey)
. "&oauth_nonce=" . urlencode($nonce)
. "&oauth_signature_method=" . urlencode($signatureMethod)
. "&oauth_timestamp=" . urlencode($timestamp)
. "&oauth_token=" . urlencode($accessToken)
. "&oauth_version=" . urlencode($version);
$base = $base.urlencode($baseparams);
$key = urlencode($consumerSecret) . '&' . urlencode($tokenSecret);
$signature = hash_hmac('sha256', $base, $key, true);
$signature = urlencode(base64_encode($signature));
return $signature;
}
My execute function:
function execute($options = array()){
Global $consumerKey, $accessToken, $consumerSecret, $tokenSecret, $realm, $signatureMethod, $version;
$curl = curl_init();
echo $options['url'];
curl_setopt_array($curl, array(
CURLOPT_URL => $options['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1
));
$timestamp = round(microtime(true));
$nonce = getNonce(11);
$signature = generateSignature($options, $timestamp, $nonce);
$authHeader = 'Authorization: OAuth realm="'.$realm.'",oauth_consumer_key="'.$consumerKey.'",oauth_token="'.$accessToken.'",oauth_signature_method="'.$signatureMethod.'",oauth_timestamp="'.$timestamp.'",oauth_nonce="'.$nonce.'",oauth_version="'.$version.'",oauth_signature="'.$signature.'"';
curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, strtoupper($options['method']) );
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
$authHeader
));
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
$response = curl_exec($curl);
$array = json_decode($response, true);
echo "<br/>".$responsecode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if(curl_errno($curl)){
return 'Curl error: ' . curl_error($curl);
}
else{
return $array;
}
curl_close($curl);
}
This works fine when I have an url like this:
https://website.com/api/customer?limit=10 - WORKS
But the API also supports this:
https://website.com/api/customer?q=partner+EQUALS+10 - DOESNT WORK
When I put this URL into my function, it doesn't work and I get an 400 error instead.
My guess is that the signature is incorrect due to the spaces inside the url parameter.
How can I make this work with an url parameter that has spaces in it?
I already tried to use urlencode but that didnt work as well.
If it helps you out: I'm using the NETSUITE REST API for this.
Can someone help me plz...
When you make a req use encoded url insted of spaces.
https://website.com/api/customer?q=partner+EQUALS+10
this type will works for you
A few months ago I implemented a RESTlet solution that receives a POST request from a PHP script. I am now extending the solution to send a GET request to a RESTlet with a different ID. The issue is that the authentication is only successful when the request is sent to a URL without the query string. We need to pass the query string to the RESTlet in order for it to execute.
Appending the query string to the URL throws a 403 INVALID_LOGIN error, and calling the RESTlet without it throws an exception for a missing paramter (as expected).
private function setAuthentication() {
$oauthNonce = md5(mt_rand());
$oauthTimestamp = time();
$baseString = $this->requestType."&".urlencode($this->url)."&".urlencode(
"deploy=".$this->deployID
."&oauth_consumer_key=".$this->consumerKey
."&oauth_nonce=".$oauthNonce
."&oauth_signature_method=".$this->oauthSigMethod
."&oauth_timestamp=".$oauthTimestamp
."&oauth_token=".$this->tokenID
."&oauth_version=".$this->oauthVersion
."&realm=".$this->account
."&script=".$this->scriptID
);
$sigString = urlencode($this->consumerSecret).'&'.urlencode($this->tokenSecret);
$signature = base64_encode(hash_hmac('sha1', $baseString, $sigString, true));
$authHeader = "OAuth "
. 'oauth_signature="' . rawurlencode($signature) . '", '
. 'oauth_version="' . rawurlencode($this->oauthVersion) . '", '
. 'oauth_nonce="' . rawurlencode($oauthNonce) . '", '
. 'oauth_signature_method="' . rawurlencode($this->oauthSigMethod) . '", '
. 'oauth_consumer_key="' . rawurlencode($this->consumerKey) . '", '
. 'oauth_token="' . rawurlencode($this->tokenID) . '", '
. 'oauth_timestamp="' . rawurlencode($oauthTimestamp) . '", '
. 'realm="' . rawurlencode($this->account) .'"';
return $authHeader;
}
public function callGetRestlet() {
$this->requestType = 'GET';
$authorizationHeader = $this->setAuthentication();
$urlQueryAppend = http_build_query(array('id' => $this->queryString));
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->requestType);
curl_setopt($ch, CURLOPT_URL, $this->url. '?&script='. $this->scriptID. '&deploy='. $this->deployID.'&realm=' . $this->account);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: '.$authorizationHeader,
'Content-Type: application/json',
]);
$response = array();
$response['request'] = json_decode($this->queryString);
$response['response']['body'] = json_decode(curl_exec($ch));
$response['response']['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $response;
}
I know the credentials are okay as the RESTlet's event log shows the exception when the parameter isn't provided. The above throws the exception.
When the CURLOPT_URL is modified to include the querystring it throws the 403:
curl_setopt($ch, CURLOPT_URL, $this->url. '?&script='. $this->scriptID. '&deploy='. $this->deployID.'&realm=' . $this->account.'&'.$urlQueryAppend);
This code was slightly modified from an answer to a different question that asked about a POST request.
Is the error being thrown as a result of setting the request headers?
Adding the id parameter to the base string after the deploy ID resolved the issue. I was adding it to the end, but in this case it looks like the order of the parameters matters.
private function setAuthentication() {
$oauthNonce = md5(mt_rand());
$oauthTimestamp = time();
$baseString = $this->requestType."&".urlencode($this->url)."&".urlencode(
"deploy=".$this->deployID
."&id=".$this->queryString
."&oauth_consumer_key=".$this->consumerKey
."&oauth_nonce=".$oauthNonce
."&oauth_signature_method=".$this->oauthSigMethod
."&oauth_timestamp=".$oauthTimestamp
."&oauth_token=".$this->tokenID
."&oauth_version=".$this->oauthVersion
."&script=".$this->scriptID
);
$sigString = urlencode($this->consumerSecret).'&'.urlencode($this->tokenSecret);
$signature = base64_encode(hash_hmac('sha256', $baseString, $sigString, true));
$authHeader = "OAuth "
. 'oauth_signature="' . rawurlencode($signature) . '", '
. 'oauth_version="' . rawurlencode($this->oauthVersion) . '", '
. 'oauth_nonce="' . rawurlencode($oauthNonce) . '", '
. 'oauth_signature_method="' . rawurlencode($this->oauthSigMethod) . '", ' /** must be HMAC-SHA256 as SHA1 is deprecated **/
. 'oauth_consumer_key="' . rawurlencode($this->consumerKey) . '", '
. 'oauth_token="' . rawurlencode($this->tokenID) . '", '
. 'oauth_timestamp="' . rawurlencode($oauthTimestamp) . '", '
. 'realm="' . rawurlencode($this->account) .'"';
return $authHeader;
}
public function callGetRestlet() {
$this->requestType = 'GET';
$parameters = http_build_query(
array(
'script' => $this->scriptID,
'deploy' => $this->deployID,
'id' => $this->queryString,
)
);
$authorizationHeader = $this->setAuthentication();
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->requestType);
curl_setopt($ch, CURLOPT_URL, $this->url. '?'.$parameters);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 6);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: '.$authorizationHeader,
'Content-Type: application/json',
]);
$response = array();
$response['request'] = $this->url. '?'.$parameters;
$response['response']['body'] = json_decode(curl_exec($ch));
$response['response']['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return $response;
}
I am trying to delete object from amazon s3 with REST API.
I create a curl command but I get 403 error: "SignatureDoesNotMatchThe request signature we calculated does not match the signature you provided".
I used in AWS documentation:
https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectDELETE.html
https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
This is my code:
$host = 's3.amazonaws.com';
$url = "https://" . $bucket . '.' . $host . '/' . $file;
$date_full = date('D, d M Y H:i:s \G\M\T');
$date = date('Ymd');
$longDate = gmdate('Ymd\THis\Z');
$shortDate = gmdate('Ymd');
$credential = $accessKeyId . '/' . $shortDate . '/' . $region . '/s3/aws4_request';
$hashed_payload = strtolower(hash("sha256", ""));
$headers = [
'X-Amz-Algorithm' => 'AWS4-HMAC-SHA256',
'X-Amz-Credential' => $credential,
'X-Amz-Date' => $longDate,
'X-Amz-Expires' => 86400,
'X-Amz-SignedHeaders' => 'host',
'x-amz-content-sha256' => $hashed_payload,
'Host' => $bucket . '.' . $host,
];
ksort($headers);
$signed_headers_string = strtolower(implode(';', array_keys($headers)));
// Build canonical request
$canonical_request = "DELETE\n"; // HTTPRequestMethod
$canonical_request .= '/' . urlencode("http://s3.amazonaws.com/" . $bucket . "/" . $file) . "\n"; // CanonicalURI
$canonical_request .= "\n"; // CanonicalQueryString
foreach ($headers as $header => $value) {
$canonical_request .= strtolower($header) . ':' . trim($value) . "\n"; //CanonicalHeaders
}
$canonical_request .= $signed_headers_string . "\n"; // SignedHeaders
$canonical_request .= $hashed_payload; // HashedPayload
// Build string to sign
$string_to_sign = "AWS4-HMAC-SHA256\n";
$string_to_sign .= $date_full . "\n";
$string_to_sign .= $date . '/' . $region. "/s3/aws4_request\n";
$string_to_sign .= hash('sha256', $canonical_request);
// Calculate signature
$signature_date = hash_hmac('sha256', $date, 'AWS4' . $secretKey, true);
$signature_region = hash_hmac('sha256', $region, $signature_date, true);
$signature_service = hash_hmac('sha256', 's3', $signature_region, true);
$signature_request = hash_hmac('sha256', 'aws4_request', $signature_service, true);
// Build Signature
$signature = hash_hmac('sha256', $string_to_sign, $signature_request);
// Calculate final Authorization header
$headers['Authorization'] = 'AWS4-HMAC-SHA256 Credential=' . $credential . ', ';
$headers['Authorization'] .= 'SignedHeaders=' . $signed_headers_string . ', ';
$headers['Authorization'] .= 'Signature=' . $signature;
// Convert headers to key:value strings
$curl_headers = array();
foreach ($headers as $header => $value) {
$curl_headers[] = "{$header}:{$value}";
}
// Init curl
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_VERBOSE, 1);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($curl, CURLINFO_HEADER_OUT, true);
curl_setopt($curl, CURLOPT_HEADER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $curl_headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
$result = curl_exec($curl);
Someone can help me please to understand what is the problem?
You are sorting keys that have upper and lower case letters. Use all lower case letters in the keys before calling ksort().
You are also including headers that don't need to be included. The documentation you referred to only asks for x-amz-date, x-amz-content-sha256, and host. Use only those headers.
$headers = [
'x-amz-date' => $longDate,
'x-amz-content-sha256' => $hashed_payload,
'host' => $bucket . '.' . $host,
];
ksort($headers);
Your canonical request should have an extra line break after adding the headers:
foreach ($headers as $header => $value) {
$canonical_request .= strtolower($header) . ':' . trim($value) . "\n"; //CanonicalHeaders
}
$canonical_request .= "\n";
I'm not sure if this change is necessary, but in $string_to_sign, I use the date format provided by $longDate, not $date_full:
// Build string to sign
$string_to_sign = "AWS4-HMAC-SHA256\n";
$string_to_sign .= $longDate . "\n";
$string_to_sign .= $date . '/' . $region. "/s3/aws4_request\n";
$string_to_sign .= hash('sha256', $canonical_request);
You are setting CURLOPT_CUSTOMREQUEST twice, first to PUT and then to DELETE. The last setting is likely the one being used, but I would remove curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); for the sake of clarity.
I have rented a number through sinch.com and while I am able to successfully send an SMS to my own verified telephone number, I am unable to send SMS to various other telephone numbers.
function sendSignInText($phone_number, $first_name) {
$key = "xxxx-xxx-xxx-xxx-xxxxxxxx";
$secret = "xxxxxxxx";
$message = $first_name . ', thanks you for signing in. We will text you when we\'re ready for you';
$phone = $phone_number;
$body = json_encode(array('From' => $rented_number, 'Message'=>$message, ));
$timestamp = date("c");
$path = "/v1/sms/" . $phone;
$content_type = "application/json";
$canonicalized_headers = "x-timestamp:" . $timestamp;
$content_md5 = base64_encode( md5( utf8_encode($body), true ));
$string_to_sign =
"POST\n".
$content_md5."\n".
$content_type."\n".
$canonicalized_headers."\n".
$path;
$signature = base64_encode(hash_hmac("sha256", utf8_encode($string_to_sign), base64_decode($secret), true));
$authorization = "Application " . $key . ":" . $signature;
$service_url = 'https://messagingapi.sinch.com'.$path;
$curl = curl_init($service_url);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'content-type: '.$content_type,
'x-timestamp:' . $timestamp,
'authorization:' . $authorization
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$curl_response = curl_exec($curl);
// #todo: checking response / working with results
curl_close($curl);
}
It could be an issue with the number transferring from a sandbox version of the app. Sinch recommends you play in a sandbox before putting it out into production. So it was working as a sandbox version with my own personal telephone number and is still working as a production app with my own number but doesn't work with other, non-verified numbers. Any help would be greatly appreciated, thanks.
Having this code, which works:
$appsecretProof = hash_hmac('sha256', $shortLivedToken, $secret);
//init curl
$ch = curl_init();
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_USERAGENT, 'facebook-php-3.2');
//get extended user access token
$url = 'https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token' .
'&client_id=' . $appId .
'&client_secret=' . $secret .
'&fb_exchange_token=' . $shortLivedToken .
'&appsecret_proof=' . $appsecretProof;
curl_setopt($ch, CURLOPT_URL, $url);
$curlResult = curl_exec($ch);
$response_params = [];
parse_str($curlResult, $response_params);
$extendedUserToken = $response_params['access_token'];
$appsecretProof = hash_hmac('sha256', $extendedUserToken, $secret);
//get extended page access token
$url = 'https://graph.facebook.com/' . $pageId .
'?fields=access_token' .
'&access_token=' . $extendedUserToken .
'&appsecret_proof=' . $appsecretProof;
curl_setopt($ch, CURLOPT_URL, $url);
$curlResult = curl_exec($ch);
curl_close($ch);
$pageToken = json_decode($curlResult)->access_token;
How to achieve the same using the regular Facebook SDK? Googling didn't really help. Either I find nothing usable or the solutions do not work, throwing errors like "An access token is required to request this resource" or similar stuff. I already tried a lot but nothing really works.
My last approach was:
FacebookSession::setDefaultApplication($appId, $secret);
$shortLivedSession = new FacebookSession($shortLivedToken);
$shortLivedSession->getLongLivedSession();
$request = new FacebookRequest($shortLivedSession, 'GET', '/' . $pageId . '?fields=access_token');
$response = $request->execute();
$result = $response->getGraphObject()->asArray();
$pageToken = $result['access_token'];
$facebookSession = new FacebookSession($pageToken);
This code always returns a short-lived token.
Figured it out and #luschn, there seems to be the same error in the code on your blog.
What helped was to replace these two lines:
$shortLivedSession->getLongLivedSession();
$request = new FacebookRequest($shortLivedSession, 'GET', '/' . $pageId . '?fields=access_token');
with these:
$longLivedSession = $shortLivedSession->getLongLivedSession();
$request = new FacebookRequest($longLivedSession, 'GET', '/' . $pageId . '?fields=access_token');