I am working with a third party service that requires me to authenticate through OAuth1 to make requests. I can successfully authenticate and get data back with most of their calls using GET, however some calls they require POST and this is where the problem lies. To authenticate I am using the below:
$oauth = new OAuth(MY_KEY,MY_SECRET);
$oauth->setNonce(rand());
$oauth->setToken('','');
Then for a GET call I am doing something like below:
$array = array(
'partnerId'=>'1234'
);
$call = $oauth->fetch("https://domain.co.uk/api/getInfo/",$array);
$data = $oauth->getLastResponse();
This all works perfectly, and I can print out the $data
However with POST calls:
$oauth = new OAuth(MY_KEY,MY_SECRET);
$oauth->setNonce(rand());
$oauth->setToken('','');
$oauth->enableDebug();
$oauth->setAuthType(OAUTH_AUTH_TYPE_AUTHORIZATION);
$array = array(
'rid' => "$restaurantId",
'datetime' => "$datetime",
'partysize' => $covers,
'timesecurityID' => "$securityId",
'resultskey' => "$resultskey"
);
$call = $oauth->fetch("https://domain.co.uk/api/booking/?pid=1234&st=0",$array,OAUTH_HTTP_METHOD_POST);
$data = $oauth->getLastResponse();
I keep getting the error: Invalid Consumer Signature
Speaking to their tech guy he suggested
Your sbs value indicates that you’re signing with all of the POST
parameters, whereas you only need to sign with the query string. In
this case it would be “pid=1234&st=0”. Unfortunately, I’m not
familiar with the PHP libs and don’t have any recommendations on how
to alter the behavior.
and also mentioned common previous problems with a PHP implementation are:
The PHP HTTP lib will drop the query string once the method is
changed from GET to POST.
The PHP oAuth lib will use the post data
to sign the request rather than the query string or maybe both.
If I dump out the headers I get:
[sbs] => POST&https%3A%2F%2Fdomain.co.uk%2Fapi%2Fbooking%2F&datetime%3D2013-02-21T10%253A30%253A00%26oauth_consumer_key%3DMySiteV3TT%26oauth_nonce%3D1213111151%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1360835965%26oauth_token%3D%26oauth_version%3D1.0%26partysize%3D2%26pid%3D1531%26resultskey%3DfoqgEnYK%25252bIzRd6BV3T8eGQ%25253d%25253d%26rid%3D31852%26st%3D0%26timesecurityID%3D349367809
[headers_sent] => POST /api/booking/?pid=1234&st=0 HTTP/1.1
It looks like it is sending the OAuth data with the rest of the post, I just want this sent in the Authorization header (which it is also sending)
Authorization: OAuth oauth_consumer_key="MySite",oauth_signature_method="HMAC-SHA1",oauth_nonce="1772854358",oauth_timestamp="1360768712",oauth_version="1.0",oauth_token="",oauth_signature="2%2B7xb%2BJ5cdbUDC5UHfsdfsNpFM1pE%3D"
So I think I need to strip the OAuth data from the post request but keep it as a Authorization Header but just can't find the magic way to do that!
I've seen this. In fetch(), try urlencoding your $array and passing it in as a string of the form:
rid=[restaurantId]&datetime=[datetime]&...
Also give the header (final parameter of fetch()):
Content-Type: application/x-www-form-urlencoded
Related
I am trying to post some data using a Guzzle Client Http request in Laravel. But for some reason the server respons with the message that it can't find the property Id in the JSON object, while the property Id is clearly in the request. The Guzzle documentation says that assigning the array to a json property in the request will result in a Json object being sent.
$url = "https://blablabla.com/api";
$key = "1234";
$data = [
'Id' => "4"
];
$response = Http::withHeaders([
"Authorization" => $key
])->post($url, [
'json' => $data
]);
Now I have tested the api in Postman and don't experience any problems. I even use the same api in a different php application using curl and it works perfect. So obviously there is something wrong with lines of code above and not with the api. I have tried different things but nothing works.. I have a feeling that the solution is so simple.. but for the last 6 hours I couldn't figure it out.. So please help before I go crazy :)
Laravel documentation on page HTTP Client says: "By default, data will be sent using the application/json content type". So you don't need to use 'json' property in post data. Just sent it directly: ->post($url, $data).
My code makes a curl request to an API that converts image formats e.g. png to jpg.
The API documentation offers a callback from the API which, when the conversion is finished, will send a GET request to a url on my server (hosted, not localhost). I provide this url to the API with the key/value pair:
"callback" => "12coins.net/cc_callback.php"
Unfortunately the API never calls back. Are my curl_setopt parameters wrong or what could be the problem?
$ch_start_process = curl_init();
$start_process_data = array(
"callback" => "https://12coins.com/cc_callback.php",
"input" => "download",
"file" => "https://12coins.com/photo_file.png",//the image I want converted
"tag" => "tag - unused for now",
"outputformat" => "jpg");
$process_url = "https:".$url_from_create;//prepend https to construct a valid endpoint.
//$url_from_create is a url returned by the API to a request immediately prior to this one
curl_setopt($ch_start_process, CURLOPT_URL, $process_url);
curl_setopt($ch_start_process, CURLOPT_POSTFIELDS, http_build_query ($start_process_data));
curl_setopt($ch_start_process, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch_start_process, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4 );
$start_response=curl_exec($ch_start_process);//assign return value of curl_exec()
This is the script on my (remote) server 12coins.net/cc_callback.php to which the API should call back but doesn't:
<?php
header('Access-Control-Allow-Origin: *');
echo 'cc_callback has been called';
echo 'The GET request from CloudConvert is: '. $_GET;
?>
The API does in fact make a call back. It was just that with the code as shown in cc_callback.php there was no way for me to detect the callback. I had assumed that the echo statements would allow me to see the API's response in the (Chrome) network tab of my brower's dev tools. But of course the echo statements echo to the client that 'called' it with a GET request. In this case, that client is the API and not my browser/html page.
Realising this, I was then easily able to check that it had worked all along by adding
mail(myemailaddress#gmail.com, 'This is the url returned to the callback',$GET[url]); to my php script (shown in the question). This sent me an email when I sent an image to the API for processing and thus confirmed that the API was making the call back..
The curl code in the question is good. It makes a successful request to the API.
Lastly, the curl code is for a request to the CloudConvert API, version 1. There is a version 2 but the code above is not good for that. Also, there's an earlier curl request which must be used in conjunction with the one above which I'll post later for the sake of completeness.
I'm trying to create a "service" like application, which can be able to receive API calls from another services. (These services will be built, for different purposes). And also able to send API calls to an another one.
Each request that they send, and accept has to have the following format.
{
header : {
// some header information, like locale, currency code etc.
signature : "some-hashed-data-using-the-whole-request"
},
request : {
// the usable business data
}
}
To each request I want to append a hash, that is generated from the actual request or anyhow (salted with password or any kind of magic added). Its not that important at the moment. I gave the name signature to this field. So for each received request, I want to reproduce this signature from the request. If the signature I received is matching with the one I generated, I let the application run otherwise showing some error message.
I already read a few articles, but most of them is for user-pass combinations.
My question is not about that if it's a good solution or not. I just want to know how can implement a middleware like functionality - like in laravel - in Symfony 4?
Instead of putting headers into a JSON object the HTTP body, use HTTP headers directly. That’s what they are for. When you’re using non-standard headers, prefix them with X- and maybe a prefix for your application, for example X-YourApp-Signature. The request goes into the body, i.e. the value of the request property in your example.
The server side is pretty simple with Symfony:
public function someAction(Request $request)
{
$signature = $request->headers->get("X-YourApp-Signature");
$data = json_decode($request->getContent());
// ... go on processing the received values (validation etc.)
}
If you want to write a HTTP client application in PHP, I would recommend using the Guzzle library. Here’s an example:
$headers = ["X-YourApp-Signature" => "your_signature_string"];
$data = json_encode(["foo" => "bar"]);
$request = new \GuzzleHttp\Psr7\Request("POST", "https://example.com", $headers, $data);
$client = new \GuzzleHttp\Client();
$response = $client->send($request, ["timeout" => 10]);
var_dump($response);
Of course, you’ll also want to implement some error handling etc. (HTTP status >= 400), so the code will be a bit more complex in a real application.
As k0pernikus mentioned, the before after filters solves my issue.
I'm making a request to retrieve a JSON file to a server at a particular secure DocuSign uri. However, unless I put in the authorization information (which I do have), I am unable to have the file returned.
<?php
$json = file_get_contents("https://example.docusign.com/sensitiveIDs/moreID");
echo $json
?>
Where would I put in authorization information for the specific server/username/password/other info needed to access the particular DocuSign server using a method like this in PHP? Is there a better method to use for this scenario in PHP?
It depends on how the authorization is implemented. If its basic or digest HTTP authentication then specify it in the URL:
file_get_contents("https://$USER:$PASSWORD#example.docusign.com/sensitiveIDs/moreID");
Cookie based authentication is a lot more difficult (and probably easier to use Curl or even a more complex system like Guzzle. If its oauth2, then you probably want an oauth2 library.
Your call needs to include authentication to make the GET call to retrieve the file.
If your app is initiated by a human use Oauth to retrieve access and refresh tokens. Then included the access token with the GET request.
If your app is a "system app" that wants to autonomously retrieve the file, then you should authenticate by using X-DocuSign-Authentication -- include the following header in your HTTPS request. Since the request is HTTPS, the content is encrypted on the wire:
X-DocuSign-Authentication: <DocuSignCredentials><Username>{name}</Username><Password>{password}</Password><IntegratorKey>{integrator_key}</IntegratorKey></DocuSignCredentials>
Replace {name} with your email address (no braces), etc.
The bottom line is that you can't use the file_get_contents Php method. Instead, you'd do something like the following:
Use https://github.com/rmccue/Requests or a similar library to help with the https request. (http is not allowed due to security issues.)
(untested code)
$url = $base_url . $the_url_section_for_this_call
$headers = array('X-DocuSign-Authentication' =>
'<DocuSignCredentials><Username>your_name</Username><Password>your_password</Password><IntegratorKey>your_integrator_key</IntegratorKey></DocuSignCredentials>');
$request = Requests::get($url, $headers);
# Check that the call succeeded (either 200 or 201 depending on the method
$status_code = $request->status_code;
if ($status_code != 200 && $status_code != 201) {
throw new Exception('Problem while calling DocuSign');
}
$json = $request->body;
I have been given a URL that I need PHP to post data to, anonymously, without the end user knowing about it.
The exact structure is:
https://example.com/api/rest/example/createSubscription?email=1#1.com&subscriberNumber=12345JD&subscriberGroup=shop&firstName=Joe&lastName=Bloggs&offerCode=ex1&licenseParameters="STARTDATE%3D2014-08-11%26ENDDATE%3D2014-09-11"
Obviously this is a dynamic URL and I have set it up to be. I am not sure about the best way to approach this issue. Would it be a PUT http_request? I have tried that using the following but it returns a 400 error.
$url = 'https://example.com/api/rest/example/createSubscription?email=1#1.com&subscriberNumber=12345JD&subscriberGroup=shop&firstName=Joe&lastName=Bloggs&offerCode=ex1&licenseParameters="STARTDATE%3D2014-08-11%26ENDDATE%3D2014-09-11"';
$options = array(
'method' => 'PUT',
'timeout' => 15,
'header' => "Content-type: html/txt",
);
$response = http_request($url, $options);
As for your last comment, if the subscription is created simply opening the url in the browser then it is a GET request.
You can perform a GET request using file_get_contents
It's really strange you use PUT method with GET paramater.
After checking php manual here you don't use correctly this methode. that's why the server can't understand your request.
you can look after this function to do a PUT request