PHP cURL Malformed Authorization header REST API Basic Authorization - php

I try to make HTTP request to my vendor API using curl Basic Auth like this :
//Server url
$url = "https://api.example.com/store/products?status=all&offset=0&limit=50";
$apiKey = 'xxxxxxx'; // apikey
$headers = array(
'Authorization: Basic '.$apiKey
);
// Send to Server
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Get response
$response = curl_exec($ch);
// Encode : decode returns string error so use encode
echo $result = json_encode($response);
With this code I get error :
"{\"code\":400,\"result\":\"Malformed Authorization
header.\",\"error\":{\"reason\":\"BadRequest\",\"message\":\"Malformed
Authorization header.\"}}"
I looked everywhere for solution here and here. All the answers suggest adding username and password which is not necessary with my vendor API, only Api Key and header Basic Auth. What am I doing wrong?

in HTTP Basic Auth, the credentials are supposed to be base64-encoded, are you base64-encoding the key?
Also, in http basic auth, the username and password is separated by a :, is your API key supposed to go as the username or as the password? and what are you sending it as, are you sending it as the username or are you sending it as the password? (if your api key goes before the : then you're sending it as the username, if your key goes after the : then you're sending it as the password), try switching them up, does it work then?
and you're saying http basic auth, but if the API documentation does not explicitly state if the api key goes as the username or the password, i'm not convinced that they're really using http basic auth at all..
anyway, the HTTP Basic Auth specifications can be found here: https://www.rfc-editor.org/rfc/rfc7617

Related

Unable to connect to Microsoft Dynamics CRM with PHP and Curl

I am trying to use PHP and CURL to connect to Microsoft Dynamics API so I can read client data from the CRM. The API guide can be found here:
https://msdn.microsoft.com/en-gb/library/mt593051.aspx
I've been into the Azure portal and set up a new application, and it gives me the credentials to use (client id, secret, etc.) and the url end points. Using these credentials I am able to successfully connect to the CRM and retrieve a bearer access token, but I am unable to get any further.
When I attempt to use the token to return data I receive the below error message:
HTTP Error 401 - Unauthorized: Access is denied
My assumption would be that I must be passing the token correctly?
My code is below.
<?php
// Step 1 - Use the credentials supplied by CRM to get an access token (this bit works okay)
$credentials = array(
'grant_type'=>'client_credentials',
'username'=>'xxxxxxxx',
'password'=>'xxxxxxxx',
'client_id'=>'xxxxxxxxxxxx',
'client_secret'=>'xxxxxxxxxx',
);
$urlSafeCredentials = http_build_query($credentials);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'https://login.microsoftonline.com/xxxxxxxxxxxxxx/oauth2/token');
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $urlSafeCredentials);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
$response = curl_exec($ch);
$result = json_decode($response);
curl_close($ch);
// A BEARER access token is successfully returned
$token = $result->access_token;
// Step 2 - Use the access token to request data from the CRM (this bit fails with HTTP Error 401 - Unauthorized: Access is denied)
$ch = curl_init('https://clientspecificurl.crm4.dynamics.com/api/data/v8.1/accounts');
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json', 'Content-Type: application/x-www-form-urlencoded','Authorization: Bearer '.$token));
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);
print_r($response); // 401 Unauthorized ?!
?>
As far as I can tell there is nothing else to configure at the back end, any help would be much appreciated.
Based on the parameters to acquire the token, you were mixing the client credentials flow and resource owner password flow and lack of resource parameter.
The client credentials flow requires parameters grant_type,client_id,client_secret,resource and the value of grant_type is client_credentials.
The resource owner password credentials flow requires grant_type,client_id,client_secret,username,password,resource and the value of grant_type is password.
If you were using the client credentials flow, you can refer this blog for acquiring the token. And if you were using the resource owner password, you can refer this thread.
Details about difference of the flows in Oauth 2 please refer RFC 6749.
I wrote a lightweight PHP class for working with Dynamics 365 online Web API. You can find it here.
BTW in your code you should try "password" inside the grant_type instead of "client_credentials"

Build HTTP GET request with headers and body PHP

I need to retrieve order information from an API. This API needs to be authenticated to get a session token, which is used in all other API requests. Im not sure how to construct this request to include both an authentication and the request I want to make. Below is from the documentation:
The authenticate API returns a session token that is required to
access any of the other APIs. APIs require an HTTP header of
Authorization and a value of Bearer {session-token}
Sample Authenticate Request: https://api.whatever.com/api/v5/authenticate?apiKey=my-API-key Which returns:
{
"sessionToken":"UniqueSessionTokenHere"
}
Sample request I need to make: https://api.whatever.com/api/v5/inventory?itemNumber=ABC12345
Which should return inventory information but is just returning this message:
Authorization has been denied for this request.
How can I combine these to allow me to make the inventory request I need to make? I assume I would use cURL, but I cant quite figure it out.
You can use curl_setopt() with CURLOPT_HTTPHEADER to set custom headers.
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://www.google.co.in");
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
'sessionToken:UniqueSessionTokenHere'
));
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec($curl);
curl_close($curl);

Twitter application oauth started returning error code 89 Invalid or expired token after 1 year working

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!

Authorization header is not set with PHP cURL

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==

How to provide Youtube authentication token in PHP cURL

Following this guide, I'm trying to retrieve a Youtube user's subscriptions. I am able to get the user's authentication token, however I don't know HOW to actually send it with my cURL request. The docs just say this:
To request a feed of the currently logged-in user's subscriptions,
send a GET request to the following URL. Note: For this request, you
must provide an authorization token, which enables YouTube to verify
that the user authorized access to the resource.
https://gdata.youtube.com/feeds/api/users/default/subscriptions?v=2
When I send the request without the token I get the 401 user authentication required error. I can't find any information on how to send the token. Here's my current code:
$ch_subs = curl_init();
curl_setopt($ch_subs, CURLOPT_URL, 'https://gdata.youtube.com/feeds/api/users/default/subscriptions?v=2');
curl_setopt($ch_subs, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch_subs, CURLOPT_SSL_VERIFYPEER, false);
$subs_return = curl_exec($ch_subs);
curl_close($ch_subs);
Thanks in advance for any help.
Look to this guide:
https://developers.google.com/youtube/2.0/developers_guide_protocol#OAuth2_Calling_a_Google_API
You need to add a header containing: Authorization: Bearer ACCESS_TOKEN
$headers = array('Authorization: Bearer ' . $access_token);
curl_setopt($ch_subs, CURLOPT_HTTPHEADER, $headers);
You can also pass the token as part of the Get request:
curl_setopt($ch_subs, CURLOPT_URL, 'https://gdata.youtube.com/feeds/api/users/default/subscriptions?v=2&access_token=' . $access_token);

Categories