Unable to connect to Microsoft Dynamics CRM with PHP and Curl - php

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"

Related

Connect Zoom with Codeigniter (curl)

I want connect Zoom with Codeigniter, but I have a problem.
I created a ZOOM app (Waiting for Zoom approval) and I have a client id and redirect_uri.
I defined client_id, client_secret and redirect_uri.
$hash = base64_encode($client_id . ':' . $client_secret);
$headers = array(
'Authorization: Basic ' . $hash
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://zoom.us/oauth/authorize?response_type=code&client_id='.$client_id.'&redirect_uri='.$redirect_uri);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
//curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array('data'=>($data))));
$result = curl_exec($ch);
$all=json_decode($result);
print_r($all);
When I execute this code, I got stdClass Object ( [status] => [errorCode] => 202 [errorMessage] => Something went wrong. Please refresh this page. [result] => ).
Can you help me? Thank you!!
It looks like you're mixing up two steps of the OAuth process.
The OAuth flow should look like this:
You redirect your user to the authorize URL (the URL you have listed in your request) with your client_id, grant_type, redirect_uri, and scope.
The OAuth provider (Zoom) redirects your user back to your redirect_uri with a query string parameter of code
You make a POST request to the token endpoint with your client_id and client_secret in the Authorization header (which you have in your $headers variable) and the code, redirect_uri, and grant_type in the body (url form encoding, typically). The return value of this request includes the access token (and refresh token).
It looks like you mixed up the request in #1 with the request in #3.
You might consider using a managed OAuth service to do this for you, like Xkit where I work. There you just have to provide your Zoom OAuth credentials and they handle all the redirects, requests, etc. All you do is make an API call to Xkit and they'll return an access token. Here's their Zoom Setup guide for reference.

LinkedIn API v2 not returning data

I set up an app on linkedIn. Set up and tested code to return an access token. Which all worked fine. I tried to get basic profile data and it says I do not have proper access rights. I gave the app all basic permission other than write posts so I am at a loss for why nothing is being returned.
The error:{"serviceErrorCode":100,"message":"Not enough permissions to access: GET /me","status":403}
My code is below.THETOKENWOULDBEHERE in the live code is the token returned by the oauth process. If anyone has any insights it would be appreciated.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.linkedin.com/v2/me");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-RestLi-Protocol-Version:2.0.0','x-li-format: json','Authorization: Bearer *THETOKENWOULDBEHERE*'));
$response = curl_exec($ch);
curl_close($ch);
print_r($response);
If you are using V2 and you did not taken permission to use r_basicprofile
then either apply for permission to use r_basicprofile to linkedin
or use r_liteprofile + r_emailaddress
Check this : https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/migration-faq?context=linkedin/consumer/context

Firebase custom token php server generation error

I have installed the package recommended by firebase for php custom tokens which can be found here, https://firebase.google.com/docs/auth/admin/create-custom-tokens found under the heading Create custom tokens using the third-party JWT library.
I have installed the php-jwt advised.
I then created a service account found here and in the /apis/credentials I get similar details as below which I downloaded.
"private_key": "-----BEGIN PRIVATE KEY-----veryLongKey---END PRIVATE KEY-----\n",
"client_email": "randomemail#appspot.gserviceaccount.com",
I then generate a token using the format illustrated by the link at the top.
However when I put that $theCreatedToken in this curl ....
$url = 'https://localhost-42d67.firebaseio.com/Devices.json?auth=' .$theCreatedToken;
$arr = array("success" =>array("iPhone"=>500));
$data_string = json_encode($arr);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string))
);
echo $result = curl_exec($ch);
I get this error
{
"error": "Expected an ID token, but was given a custom token."
}
If I remove the ?auth=' .$theCreatedToken; it works.
What am I doing wrong? I have searched this extensively but there is no answer.
I hope someone is able to help.
Best
It's pretty confusing, but I got it worked by using this library and the service accounts JSON generated in Firebase settings.
https://github.com/kreait/firebase-php
I also wrote this library to make it work with Guzzle 5 and PHP 5.6
https://github.com/luqmanrom/firebase-php
Apparently, it uses Bearer token in Authorization header instead of passing the auth token in query strings. The token is fetched from the Google OAuth2 server.
Hopefully it helps

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!

How do I use LinkedIn Oauth1.0a token for requests? (Exchanged from JSAPI token)

I am really stuck with this. I have exchanged the token returned by the LinkedIn JSAPI up to step 3 where I receive the oauth_token and oauth_token_secret. I am using the oauth-php library from here and following instruction from LinkedIn and SO. In the LinkedIn docs step 4 uses the pecl oauth library to set the token and token secret. Oauth-php doesn't have seem to have a similar method. My token looks similar to this 00--xx11xx22-123a-0000-0a0a-12312asda1231asd so not really like the OAuth 2.0 tokens.
I am trying to call this method with my exchanged oauth_token, but I keep getting an invalid token response. Clearly I am missing some step. Any help at all is greatly appreciated.
function linkedin_api_get($exchanged_oauth_token) {
$url = 'https://api.linkedin.com/v1/people/~';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, "MyLinkedInConnect");
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer " . $exchanged_oauth_token,
"x-li-format: json"
));
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response);
}
I guess this token can't be used as a bearer. But how do I exchange this token to a bearer token? Or how do I use the oauth token and oauth token secret correctly without the PECL oauth library?

Categories