I'm trying to make an API-call from PHP using cURL.
This is my code:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://localhost/api/");
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(array('sql' => $sql)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: MY-API-KEY'));
$response = curl_exec($ch);
curl_close($ch);
It seems as if the Authorization-header is not set. I've tried to Google around, where some say that the header is not recognized correctly. Can anyone help?
My code does work for API-calls without Authorization needed.
UPDATE:
Calling the command via the command line tool curl:
curl -H 'Authorization: MY-API-KEY'...
everything works.
My feedback from the PHP cURL is "Access denied".
Because it does't look its constructed properly:
Client side:
When the user agent wants to send the server authentication credentials it may use the Authorization header.
The Authorization header is constructed as follows:
Username and password are combined into a string "username:password"
The resulting string is then encoded using the RFC2045-MIME variant of Base64, except not limited to 76 char/line
The authorization method and a space i.e. "Basic " is then put before the encoded string.
For example, if the user agent uses 'Aladdin' as the username and 'open sesame' as the password then the header is formed as follows:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Related
I am trying to use an API which says to use it in a custom application to set a custom referer. Here's the official text:
The API requires (if enabled) a token for read operations to be send
to allow request, otherwise "Missing 'key' parameter" message will be
returned.
The security module will use the referrer heading ("referer" in Java,
HTTP_REFERER in PHP) of the request to identify and filter the
authorized domains.
I can currently log in to the web interface by using a special URL provided which seems to set the session and then redirects to the main URL. If I try navigating to the main URL directly without first using the special URL, I get a 401 error, as expected (afterwards, I can just use the main URL)
The key given below the text above is something like: http://example.com/api/?key=secretkeyhere
While I can use the API using the GUI tool in my web browser as described above, I can't figure out how to connect to it programatically. I have tried using both curl in Linux as well as curl in PHP. Both have failed.
curl from terminal:
curl --header http://example.com/api/?key=secretkeyhere http://example.com/api/search?query=terms*
curl in PHP:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com/api/search?query=terms');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, 'http://example.com/api/?key=secretkeyhere');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_AUTOREFERER, true);
$html = curl_exec($ch);
curl_close($ch);
echo "$html";
?>
I continue to get:
Unauthorized This server could not verify that you are authorized to
access the document requested. Either you supplied the wrong
credentials (e.g., bad password), or your browser doesn't understand
how to supply the credentials required.
Am I doing something wrong here? Is the API not set up correctly? I've read the man page for cURL and it seems like this is exactly what I should be doing.
I've been going round in circles trying to get this bit of code working. The problem I am facing is that there could be any number of places where something is wrong and I'm not experienced enough with cURL and API requests to know if I've just done something simple and silly somewhere. The code below is supposed to fetch a JSON response. What I am currently getting is "false". The API developer keeps giving me a CLI sample and I don't know how to "translate" that into something I can use in PHP.
I have to hide the domain, service name and authentication details in my examples.
The string I was given:
'https://[domain]/agw/latest/services/[service]-api/latest/api/v2/[service]-actual-prizes -vk -H "Proxy-Authorization: Basic [authstr]"'
([authstr] is the username and password, separated by a colon and BASE64 encoded - the API dev has confirmed that my authorisation string is correct)
What I have been trying:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://[domain]/agw/latest/services/lottery-api/latest/api/v2/sportka-actual-prizes');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Proxy-Authorization: Basic '.$authstr.'"
,"Content-type: application/json"
));
$response = curl_exec($ch);
curl_close($ch);
var_dump($response);
If I understand this correctly (and I'm not sure that I do), then I'm passing the URL (without flags), saying that I don't want a header in the response (I've tried TRUE as well without any success) and then passing headers with my request that includes the authorisation.
I've tried file_get_contents with a stream_context_create header but that fails too.
Am I missing a header option or flag or something in my cURL code?
I using PHP cURL to communicate with a Rest API. Most of the functionality is carried out using X-Ephemeral-Tokens, but unfortunately they don't allow delete permissions to be given through these, so I am having to implement a function to delete through HTTP Basic Authentication.
The trouble I'm having is that the password for the testing account is a random string, including multiple special characters (double quotation marks being some of them). I got the request working using the normal cURL binary by surrounding the username:password combination in single quotes (i.e. ') but I'm not sure how to convert this to PHP. The relevant snippet is below.
$curl = curl_init();
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Accept: application/json",
"Content-Type: application/json"));
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, $uname . ":" . $pass);
curl_setopt($curl, CURLOPT_URL, "https://cloud.ravellosystems.com/api/v1/applications/" . $appid);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
$result = curl_exec($curl);
I've tried various combinations of quotation marks and URL encoding but I still get a response code which indicates the authentication isn't working right.
This is and exmaple HTTP request based on what the API documentation shows for using normal cURL (amended slightly)
curl -v -X DELETE -H "Content-Type: application/json" -H "Accept: application/json" --user ravello#ravello.com:password https://cloud.ravellosystems.com/api/v1/applications/414244
Any suggestions on how to get around this greatly appreciated.
Ok so if anyone else has this issue, I've found a solution.
Basically you can see in my code above that I was trying to use the cURL PHP methods to set options for CURLOPT_USERPWD and CURLOPT_HTTPAUTH. However somewhere in this the special characters in the password were causing issues with the parsing and I think only a section of it was actually being taken by the server.
However, all that these options do basically is set an HTTP header, as can be seen in #mpyw screenshots. This is the Authorization header, which is in the format below:
`Authorization: Basic [base64 encoded username:password]`
So I got rid of these options and did it manually, by base64 encoding my username:password string myself and then adding a header.
$auth = base64_encode($uname . ":" . $pass);
curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: Basic $auth",
"Accept: application/json",
"Content-Type: application/json"));
Now it all works fine! Thanks to the guys who posted answers - both of you contributed to me coming up with the workaround.
I compared two ways, enabling verbose outputs.
Emitted headers are the same, except that the PHP does not contain User-Agent header. Does the API require User-Agent header?
Edit
Password that contains '
Password that contains "
I believe that you have to base64_encode the username and password. Try this:
curl_setopt($curl, CURLOPT_USERPWD, base64_encode($uname . ":" . $pass));
The endpoint I'm trying to reach requires HTTPS and Basic Authentication. My team was given an API key, and the documentation states to use the key as the username, and to leave the password blank.
Here is the example CURL request from the documentation:
curl -i -k -u '<api_key>': -XPOST --data-urlencode data#/path/to/test/file.json "https://<your_subdomain>.vendor.org/api/v1/assessments/import"; echo ""
When I execute the following using the Postman extension for Chrome, I get a successful response from the server:
I'm trying to execute this locally using PHP (XAMPP install). The following is getting a response from the server saying the username/password is incorrect:
function curlPost($url, $headers, $username, $password, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CAINFO, 'certificate.pem');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
print_r(curl_exec($ch));
// print_r(curl_getinfo($ch));
// print_r(curl_error($ch));
curl_close($ch);
}
$data = '{"key":"value", "key":"value"}';
curlPost('https://domain.com/api/data', ['Content-Type: application/xml'], 'api_key', '', $data);
{"success":false,"errors":["Email\/Username or password incorrect. Please try again."],"warnings":[],"info":[],"meta":[],"results":[]}
The JSON string used in $data was copied and pasted from a successful Postman request.
The certificate.pem is in the same folder as the script, and read/write permissions have been given to everyone. I have tried exporting the specific certificate for our vendor's site from my machine as well as the CA bundle linked in the top response to this post. I was able to use it to successfully hit the vendor's api-key-test endpoint via PHP/CURL.
I'm pretty new to this. Would you mind helping me wrap my head around what I'm missing? While I've copied and pasted a ton, the function is largely my own. The parameter for headers will be used for other things.
Basic Authentication with the HTTP Authorization header uses the Base64 encoded value of "username:password" (without the double quotes)
So I'm assuming in your case you would need to Base64 encode "yourApiKeyValue:" and put that in a Authorization header in your cURL command
MDN reference - HTTP Authentication
Edit: This may also be helpful
How do I make a request using http basic authentication-with-php-curl
I've been using code based on Jon Hurlock's Twitter Application-only Authentication App for over a year now with no problem, and about 2 days ago it started returning this error when trying to generate a bearer token:
Invalid or expired token, code:89
My code is slightly altered to force it to check for SSL, since the page is not on an SSL-enabled domain. I have curl pull in the latest cacert.pem file.
This is application level oauth, NOT individual person oauth. So each time a call is made I generate a bearer token, make an API call, and then invalidate the bearer token. You can see his original code here (I pulled the latest version for the part I use): https://github.com/jonhurlock/Twitter-Application-Only-Authentication-OAuth-PHP/blob/master/Oauth.php
THis is the code used to get a bearer token. Note I only have to include the Application's key and secret, there is no user involved and a user never has to allow the app nor authenticate it:
// Step 1
// step 1.1 - url encode the consumer_key and consumer_secret in accordance with RFC 1738
$encoded_consumer_key = urlencode(CONSUMER_KEY);
$encoded_consumer_secret = urlencode(CONSUMER_SECRET);
// step 1.2 - concatinate encoded consumer, a colon character and the encoded consumer secret
$bearer_token = $encoded_consumer_key.':'.$encoded_consumer_secret;
// step 1.3 - base64-encode bearer token
$base64_encoded_bearer_token = base64_encode($bearer_token);
// step 2
$url = "https://api.twitter.com/oauth2/token"; // url to send data to for authentication
$headers = array(
"POST /oauth2/token HTTP/1.1",
"Host: api.twitter.com",
"User-Agent: Twitter App-Only Search",
"Authorization: Basic ".$base64_encoded_bearer_token,
"Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
);
$ch = curl_init(); // setup a curl
curl_setopt($ch, CURLOPT_URL,$url); // set url to send to
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); // set custom headers
curl_setopt($ch, CURLOPT_POST, 1); // send as post
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // return output
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, True);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, "/directory/path/cacert2014.pem");
curl_setopt($ch, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
$header = curl_setopt($ch, CURLOPT_HEADER, 1); // send custom headers
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$retrievedhtml = curl_exec ($ch); // execute the curl
curl_close($ch); // close the curl
Here is what I found (using the same library from John Hurlock). The Bearer Token should be cached.
This particular implementation will ask for a new Bearer Token for every request, Twitter expects that we will cache this token and will return errors and sometimes a 403 forbidden if we do not.
In my case I turned off twitter for a period of time on the site, and then after caching the Bearer Token turned it back on. Everything is back for now. You could also switch to a new twitter app in your developer console instead of waiting.
I cached my Token in Memcache, but you may choose to do something different.
Good luck!