LinkedIn Get Token Access via PHP cUrl Fail - php

I try to create a register function with linkedIn in my website.
As you know, linkedIn has 2 step authentication to get Access token.
See StackOverflow answer here : Click here
From the thread above,
i try to do the second step with PHP cUrl.
$url = "https://www.linkedin.com/oauth/v2/accessToken?grant_type=authorization_code&code=" . $_GET['code'] . "&redirect_uri=A_URL&client_id=MY_CLIENT_ID&client_secret=SECRET";
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $url,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_TIMEOUT => 1000,
CURLOPT_HTTPHEADER => array(
"Content-Length: 1000"
)
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if (!$err) {
$response = json_decode($response);
} else {
throw new exception(__METHOD__ . '() ' . $err . ', on line : ' . __LINE__);
}
but when the curl_exec() is executed, the page goes to loading infinitely.
I do not know what's my mistake. I try to run the $url manually via the url box, it return a token and expired time successfully. So, i conclude the mistake is in the cUrl.
Any help guys ?,
Thank you very much.

CURLOPT_CUSTOMREQUEST => "GET"
and delete CURLOPT_HTTPHEADER option, It's useless.

Related

How to send a message to specific connectionId to aws api gateway websockets?

I am using this code to establish a new connection on user device.
var socket = new WebSocket("wss://cdsbxtx2xi.execute-api.us-east-2.amazonaws.com/test");
socket.onmessage = function (event) {
json = JSON.parse(event.data);
connectionId = json.connectionId;
document.cookie = "connection_id="+connectionId;
console.info(json);
}
Suppose from this request I get connectionId CLO5bFP1CYcFSbw=
Another user from another device also established a new connection with connectionId Cs42Fs5s5yuSbc=. Now how can I send a message from user 2 device to user 1?
I already tried this. I don't know this is right way or not but still, i am open for any suggestion.
use Aws\Signature\SignatureV4;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use Aws\Credentials\Credentials;
$client = new GuzzleHttp\Client();
$credentials = new Credentials("XXXXXXXXXX","XXXXXXXX");
$url = "https://cdsbxtx2xi.execute-api.us-east-2.amazonaws.com/test/#connections/CLO5bFP1CYcFSbw=";
$region = 'us-east-2';
$msg['action'] = 'sendmessage';
$msg['data'] = 'hello world';
$msg = json_encode($msg);
$request = new Request('POST', $url, '["json"=>$msg]');
$s4 = new SignatureV4("execute-api", $region);
$signedrequest = $s4->signRequest($request, $credentials);
$response = $client->send($signedrequest);
echo $response->getBody();
This code keeps on loading and finally throws gateway timeout error.
I expect that user 2 should be able to send message to any specific connectionId over wss or https.
I tried https by signing this request but signing doesn't works. I am getting an error with the signing part
After struggling with this problem for the last 3 days finally I found the solution. None of the previously mentioned solutions on StackOverflow was working for me.
This is the correct solution. I hope this will be helpful to someone.
use Aws\Signature\SignatureV4;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use Aws\Credentials\Credentials;
$client = new GuzzleHttp\Client();
$credentials = new Credentials(accessKeyId, secretAccessKey);
$url = "https://xsdsdsd.execute-api.us-east-2.amazonaws.com/test/#connections/CNtBveH2iYcCKrA=";
// CNtBveH2iYcCKrA= is connectionid
$region = 'us-east-2';
$msg['action'] = 'sendmessage';
$msg['data'] = 'hello world';
$msg = json_encode($msg);
$headers = array('Content-Type => application/x-www-form-urlencoded');
$request = new GuzzleHttp\Psr7\Request('POST', $url, ['Content-Type' => 'application/json'], $msg);
$signer = new Aws\Signature\SignatureV4('execute-api', $region);
$request = $signer->signRequest($request, $credentials);
$headers = array('Content-Type => application/x-www-form-urlencoded');
$client = new \GuzzleHttp\Client([ 'headers' => $headers]);
$response = $client->send($request);
$result = $response->getBody();
Hey you can use the Connection URL to send message also.
Connection url : https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/#connections
To find go to : Aws console > Api gateway > api > your_api > dashboard their you will find your connection url.
Use php cURL method because its easy and fast as compare to GuzzleHttp
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/#connections/{YOUR_CONNECTION_ID_OF_USER}',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>'{"message" : "Hello world"}',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;

How to access API from AWS API Gateway with PHP SDK 3

Can anyone help figure out how to use AWS Signature, AWS Credentials and PHP SDK 3 to access an API Gateway API? It seems like AWS Signature does not actually attach headers to a Guzzle request.
Here is my code:
<?php
require 'vendor/autoload.php';
use Aws\Credentials\Credentials;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use Aws\Signature\SignatureV4;
$access_key = '<access_key>';
$secret_key = '<secret_key>';
$url = 'https://<api-id>.execute-api.us-east-1.amazonaws.com/v1/camel?q=*';
$region = 'us-east-1';
$credentials = new Credentials($access_key, $secret_key);
var_dump($credentials);
$client = new Client();
$request = new Request('GET', $url);
var_dump($request);
$s4 = new SignatureV4("execute-api", $region);
$s4 = new SignatureV4("execute-api", "us-east-1");
$s4->signRequest($request, $credentials);
var_dump($s4);
var_dump($request);
$response = $client->send($request);
And the error I'm getting is:
( ! ) Fatal error: Uncaught exception
'GuzzleHttp\Exception\ClientException' with message ' in
/path/to/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on
line 113
( ! ) GuzzleHttp\Exception\ClientException: Client error: `GET
https://<api-id>.execute-api.us-east-1.amazonaws.com/v1/camel?q=*`
resulted in a `403 Forbidden` response: {"message":"Missing
Authentication Token"} in
/path/to/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php on
line 113
Call Stack
# Time Memory Function Location
1 0.0002 234048 {main}( ) ../access.php:0
2 0.2801 486272 GuzzleHttp\Client->send( ) ../access.php:29
3 0.3787 574224 GuzzleHttp\Promise\Promise->wait( ) ../Client.php:106
Line 29 of access.php is:
$response = $client->send($request);
It doesn't appear from the var_dumps that any headers are being added. I am able to successfully test this endpoint in the API Gateway and in Postman. Enabling CORS does not appear to make a difference.
Has anyone solved this issue yet?
This issue is also covered at https://forums.aws.amazon.com/post!reply.jspa?messageID=795522 and https://forums.aws.amazon.com/thread.jspa?messageID=774631&tstart=0 but there are no solutions there.
Thanks, Michael, for your help above.
You have to use the return from new SignatureV4, which is a modified request.
$s4 = new SignatureV4("execute-api", $region);
$signedrequest = $s4->signRequest($request, $credentials);
$response = $client->send($signedrequest);
echo $response->getBody();
Below code should work if you just want to query API GW services from php
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://<endpoint>.execute-api.us-east-1.amazonaws.com/<service>",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "{}",
CURLOPT_HTTPHEADER => array(
"Authorization: AWS4-HMAC-SHA256 Credential=<credentials>/20180705/us-east-1/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=<signature>",
"Cache-Control: no-cache",
"Content-Type: application/json",
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
?>

Sending json data to a webserver by post always return a 400

I know there are some questions like mine in stack, but I really can´t understand whats wrong with my code. If someone could look at it and give some help would be awsome.
I want to validate if the username and password given by the user are ok and if they are proceed to checkout. If not proceed to sign in a new account.
The code i have is this:
$email=$_POST['email'];
$pass=$_POST['pass'];
$pass=sha1($pass);
$jdados=array("email" => $email,
"password" => $pass);
$json_dados = json_encode($jdados);
$len = strlen($json_dados);
$file=fopen("result/test.txt", "w");
$config=array(CURLOPT_RETURNTRANSFER => "1",
CURLOPT_VERBOSE => "1",
CURLOPT_URL => $url,
CURLOPT_POST => "1",
CURLOPT_HEADER => $header,
CURLOPT_POSTFIELDS => $json_dados,
CURLOPT_CONNECTTIMEOUT =>"10"
);
$curl=curl_init($url);
curl_setopt_array($curl, $config);
$result=curl_exec($curl);
$json_result=json_decode($result);
if($result === FALSE){
die('Error: "' . curl_error($curl) . '" - Code: ' . curl_errno($curl));
}else{
curl_close($curl);
fclose($file);
}
The connection is made, but i always get the HTTP/1.1 400 Bad Request.

Google Admin SDK: You are not authorized to access this API

Since the Google Login Auth is disabled since last week I'm trying to get oAuth 2.0 working with a service account. We want to give users on our internal web application the oppurtunity to set there Out of Office.
I downloaded the lastest Google APIs Client Library for PHP. In the Google Developer Console, I have created a new project for my application and created a Service account credentials. I have also enabled the API service: Admin SDK in the Developer Console.
I have granted the account user ID access to the correct scopes (I think):
When I use the service-account.php example and change the details, I recieve an JSON with an access token, but when I do an CURL request (same as before) to get the e-mail settings from a user, the error "You are not authorized to access this API." occur.
My code:
<?php
include_once "templates/base.php";
require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php');
$client_id = '124331845-DELETEDPART-hbh89pbgl20citf6ko.apps.googleusercontent.com'; //Client ID
$service_account_name = '124331845-DELETEDPART-89pbgl20citf6ko#developer.gserviceaccount.com'; //Email Address
$key_file_location = 'globaltext-4ce09b20cb73.p12'; //key.p12
$client = new Google_Client();
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://apps-apis.google.com/a/feeds/emailsettings/2.0/'),
$key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$aOutput = json_decode($client->getAccessToken());
$strEmailAdresSplit = explode('#', "FIRSTNAME.LASTNAME#DOMAIN.EXTENSION");
$strDomein = $strEmailAdresSplit[1];
$strAlias = $strEmailAdresSplit[0];
$resConnectionJobs = curl_init();
$aHeader = array();
$aHeader[] = 'Authorization: Bearer '.$aOutput->access_token;
$aHeader[] = 'Content-Type: application/atom+xml';
curl_setopt($resConnectionJobs, CURLOPT_URL, "https://apps-apis.google.com/a/feeds/emailsettings/2.0/DOMAIN.EXTENSION/FIRSTNAME.LASTNAME/vacation");
curl_setopt($resConnectionJobs, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($resConnectionJobs, CURLOPT_HTTPHEADER, $aHeader);
curl_setopt($resConnectionJobs, CURLOPT_RETURNTRANSFER, true);
curl_setopt($resConnectionJobs, CURLOPT_HEADER, false);
$oCurlData = curl_exec($resConnectionJobs);
curl_close($resConnectionJobs);
echo $oCurlData;
?>
Are you certain your credentials are OK?
Please try the following procedure to make sure you have the right credentials.
Creating your API keys
Go to the developer's console and follow these steps:
Select your project
Choose menu item "APIs & auth"
Choose menu item "Registered app"
Register an app of type "web application"
Choose one of the following options, depending on what kind of app you're creating. Server side languages should use this option :
Key for server apps (with IP locking)
Getting access token & refresh token
Create a file that contains the following code :
<?php
if (isset($_GET['code'])) {
// try to get an access token
$code = $_GET['code'];
$url = 'https://accounts.google.com/o/oauth2/token';
$params = array(
"code" => $code,
"client_id" => YOUR_CLIENT_ID,
"client_secret" => YOUR_CLIENT_SECRET,
"redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
"grant_type" => "authorization_code"
);
$ch = curl_init();
curl_setopt($ch, constant("CURLOPT_" . 'URL'), $url);
curl_setopt($ch, constant("CURLOPT_" . 'POST'), true);
curl_setopt($ch, constant("CURLOPT_" . 'POSTFIELDS'), $params);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($info['http_code'] === 200) {
header('Content-Type: ' . $info['content_type']);
return $output;
} else {
return 'An error happened';
}
} else {
$url = "https://accounts.google.com/o/oauth2/auth";
$params = array(
"response_type" => "code",
"client_id" => YOUR_CLIENT_ID,
"redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
"scope" => "https://www.googleapis.com/auth/plus.me"
);
$request_to = $url . '?' . http_build_query($params);
header("Location: " . $request_to);
}
Now, replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with your client ID and client secret.
Make sure your scope is correct. For example, it should be https://www.googleapis.com/auth/analytics if you want to get access to Analytics.
If you run the file, you should get an OAuth2 approval screen.
If you now press Accept, you should get a result that looks like this:
{
"access_token" : YOUR_ACCESS_TOKEN,
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : YOUR_REFRESH_TOKEN
}
The result may contain additional fields, depending on which scope you're applying for.
Connecting with Google's systems in background
Once you get the above to work, your application needs to implement the following workflow:
1) Check if your input contains a GET parameter named "code". If "code" is present, get a new access token and repeat this step (refresh your page)
If "code" is not present, go to step 2.
2) Check if you have credentials stored for your service. If credentials are present, check if your access token has expired or will expire soon. Then go to step 3. If credentials are not present, go to the auth path of your service to get the auth code and go back to step 1 (make sure Google redirects to your current URL).
3) If refresh is needed, refresh your page and go back to step 1.
If refresh is not needed, you're ready to actually do what you wanted to do in the first place.
Google's PHP library takes care if the oAuth2 flow for you, however. If you're using their library, each of the steps in the 3-step process are taken care of by the library and you should just be able to do whatever you want to do with Google's services straight away. I use this strategy myself in my Google Adwords dashboard.
You can, however, just write your custom library and connect with the service directly. Herebelow is some dev code from a project I wrote a few months ago. While it doesn't work out of the box (since it's a controller that's part of a larger application), it should help you understand the flow that Google's library takes care of under the hood.
namespace Application;
class Controller_API_Google_Youtube extends Controller_API {
public function read() {
$scope = "https://www.googleapis.com/auth/youtube";
$this->doOauth($scope);
}
function doOauth($scope) {
$oauth2Credentials = JSON_File::load(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json');
$paths = array(
'token' => 'https://accounts.google.com/o/oauth2/token',
'auth' => "https://accounts.google.com/o/oauth2/auth"
);
$refreshtime = 300;
if (isset($_GET['code'])) {
// Get access code
$query = $_GET;
unset($query['code']);
if (count($query) > 0) {
$query = '?' . http_build_query($query);
} else {
$query = '';
}
$client = \PowerTools\HTTP_Client::factory(
array(
'maps' => array(
'url' => $paths['token'],
'returntransfer' => 1,
'post' => true,
'postfields' => array(
'code' => $_GET['code'],
"client_id" => $oauth2Credentials['client_id'],
"client_secret" => $oauth2Credentials['client_secret'],
"redirect_uri" => HTTP_PROTOCOL . URL_PATH . $query,
"grant_type" => "authorization_code"
)
)
)
)->execute();
$responses = $client->getResponses();
$response = array_pop($responses);
$info = $response['maps']->getInfo();
$content = $response['maps']->getContent();
if ($info['http_code'] === 200) {
$output = JSON::decode($content);
$oauth2Credentials[$scope] = array();
$oauth2Credentials[$scope]['expires'] = time() + $output['expires_in'];
$oauth2Credentials[$scope]['access_token'] = $output['access_token'];
$oauth2Credentials[$scope]['refresh_token'] = $output['refresh_token'];
file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json', JSON::encode($oauth2Credentials));
header("Location: " . HTTP_PROTOCOL . URL_PATH . $query);
} else {
echo "Something went wrong";
}
} elseif (!isset($oauth2Credentials[$scope])) {
// Get auth code
header("Location: " . $paths['auth'] . '?' . http_build_query(
array(
"response_type" => "code",
"client_id" => $oauth2Credentials['client_id'],
"redirect_uri" => HTTP_PROTOCOL . DOMAIN_PATH,
"scope" => $scope
)
));
} elseif ($oauth2Credentials[$scope]['expires'] - $refreshtime < time()) {
// Refresh access code
$client = \PowerTools\HTTP_Client::factory(
array(
'maps' => array(
'url' => $paths['token'],
'returntransfer' => 1,
'post' => true,
'postfields' => array(
"client_id" => $oauth2Credentials['client_id'],
"client_secret" => $oauth2Credentials['client_secret'],
"refresh_token" => $oauth2Credentials[$scope]['refresh_token'],
"grant_type" => "refresh_token"
)
)
)
)->execute();
$responses = $client->getResponses();
$response = array_pop($responses);
$info = $response['maps']->getInfo();
$content = $response['maps']->getContent();
if ($info['http_code'] === 200) {
$output = JSON::decode($response['maps']->getContent());
$oauth2Credentials[$scope]['expires'] = time() + $output['expires_in'];
$oauth2Credentials[$scope]['access_token'] = $output['access_token'];
file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json', JSON::encode($oauth2Credentials));
$this->read();
} else {
$this->output = array("error" => "Something went wrong");
}
} else {
$this->doSomethinguseful($oauth2Credentials, $scope);
}
return $this;
}
function doSomethinguseful($oauth2Credentials, $scope) {
// https://developers.google.com/youtube/v3/sample_requests?hl=nl
$client = \PowerTools\HTTP_Client::factory(
array(
'maps' => array(
'useragent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',
'url' => 'https://www.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true',
'returntransfer' => true,
'httpheader' => array(
'Authorization: Bearer ' . $oauth2Credentials[$scope]['access_token'],
'Accept-Encoding: gzip, deflate'
)
)
)
)->execute();
$responses = $client->getResponses();
$response = array_pop($responses);
$content = $response['maps']->getContent();
$this->output = JSON::decode(gzdecode($content));
}
}
It looks like you may be running into a problem I had as well.
The call to Google_Auth_AssertionCredentials actually requires more parameters than you're sending to work with a service account. (At least, it did in my case.)
You need to pass enough parameters to include sub (which user to take actions on account of).
Without that, I always got an access denied. This clearly isn't obvious, since there's even been a function added to the php library, loadServiceAccountJson, which is supposed to set up a service account client connection, but breaks because it doesn't set sub either.
See working code here: Google php client library loadServiceAccountJson broken - fix enclosed

Update twitter profile image using OAuth

I'm trying to get twitter update_profile_image to work using OAuth. I was using curl with regular authentication and everything was working fine, but I switched to OAuth using this library, and now everything except update_profile_image works.
I read something about twitter OAuth having problems with multipart data, but that was a while ago and the plugin is supposed to have dealt with that issue.
My working regular authentication with curl code
$url = 'http://api.twitter.com/1/account/update_profile_image.xml';
$uname = $_POST['username'];
$pword = $_POST['password'];
$img_path = 'xxx';
$userpwd = $uname . ':' . $pword;
$img_post = array('image' => '#' . $img_path . ';type=image/jpeg',
'tile' => 'true');
$format = 'xml'; //alternative: json
$message = 'Test update with a random num'.rand();
$opts = array(CURLOPT_URL => $url,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $img_post,
CURLOPT_HTTPAUTH => CURLAUTH_ANY,
CURLOPT_USERPWD => $userpwd,
CURLOPT_HTTPHEADER => array('Expect:'),
CURLINFO_HEADER_OUT => true);
$ch = curl_init();
curl_setopt_array($ch, $opts);
$response = curl_exec($ch);
$err = curl_error($ch);
$info = curl_getinfo($ch);
curl_close($ch);
My current OAuth code [I had to cut it down, so do not minor look for syntax errors]
include 'EpiCurl.php';
include 'EpiOAuth.php';
include 'EpiTwitter.php';
include 'secret.php';
$twitterObj = new EpiTwitter($consumer_key, $consumer_secret);
$twitterObj->setToken($_GET['oauth_token']);
$token = $twitterObj->getAccessToken();
$twitterObj->setToken($token->oauth_token, $token->oauth_token_secret);
try{
$img_path = 'xxx';
//$twitterObj->post_accountUpdate_profile_image(array('#image' => "#".$img_path));
$twitterObj->post('/account/update_profile_image.json', array('#image' => "#".$img_path));
$twitterObj->post_statusesUpdate(array('status' => 'This is my new status:'.rand())); //This works
$twitterInfo= $twitterObj->get_accountVerify_credentials();
echo $twitterInfo->responseText;
}catch(Exception $e){
echo $e->getMessage();
}
I've been trying to figure this out for a while, ANY help would be greatly appreciated. I'm not in any way tied to this library, so feel free to recommend others.
The version of the library I was using was outdated. Once I updated, I had to deal with a couple of other issues including 401 error due to a wrong server time, and now everything works fine. Printing out the $response->responseText helps a lot.

Categories