I am trying to get the access token so I can start building an app that works with BigCommerce. I've been following the docs here: https://developer.bigcommerce.com/api/callback. I'm using the PHP client for Bigcommerce.
The response is HTTP/1.1 400 Bad Request {"error":"Invalid client id."}.
I swear I'm using the correct client id and client secret! Or at least they are what is displayed when I click "View Client ID" on my draft app in the developer portal.
What on earth am I doing wrong?
$request = $_REQUEST;
require_once 'vendor/autoload.php';
use Bigcommerce\Api\Connection;
$tokenUrl = "https://login.bigcommerce.com/oauth2/token";
$connection = new Connection();
$connection->verifyPeer();
$connection->useUrlencoded();
$response = $connection->post($tokenUrl, array(
"client_id" => "", //I won't type it here but it is correct
"client_secret" => "", //also correct
"redirect_uri" => "https://127.0.0.1/project-custom/oauth.php", //this is the Auth Callback URL
"grant_type" => "authorization_code",
"code" => $request["code"], //when I echo these variables out they work
"scope" => $request["scope"],
"context" => $request["context"],
));
print_r($connection->getLastError());
I figured it out!
I just removed the line $connection->useUrlencoded(); because it needed to be sent as "Content-Type: application/json" and I was sending it as "Content-Type: application/x-www-form-urlencoded"
Related
I've been trying to get my PHP application to create a successful token request since finally managing to get it working with Postman as per the docs here
Apparently the API is using OAuth 2.0 which is why I expect to send up grant_type, client_id, client_secret and expires_in (if I don't specify one of these fields then the API will successfully tell me it is missing).
Now the problem I am having is with this OAuth 1.0 Authorization Header that I am having to generate, which Postman seems to have no issues doing so, however trying to do it in PHP I am just getting an error returned from the API about a signature mismatch:
array:6 [
"errorId" => "ERROR-fde4f0f1-9d5c-43fd-80eb-056cbf2c3259"
"httpStatus" => 401
"errorCode" => 401300
"message" => "Signature mismatch. Authorization signature or client credential is wrong."
"error" => "invalid_client"
"error_description" => "errorCode: '401300'. Signature mismatch. Authorization signature or client credential is wrong."
]
I've tried various debugging, a lot of which gives me different errors then I keep landing back on this one so the signature must be the problem.
I created the following class here to handle generating a header, getting some guidance from the class in the guzzle/oauth-subscriber package.
Here is an example of the request headers being generated:
array:2 [
"Content-Type" => "application/x-www-form-urlencoded"
"Authorization" => "OAuth oauth_consumer_key="XXXXXXXXXXXX",oauth_signature_method="HMAC-SHA256",oauth_timestamp="1583629976",oauth_nonce="Br2HsCVzsaEe3KswBhtCzsSxjUDWgX56",oauth_version="1.0",oauth_signature="G7%2B5f2v2Kdx3rp%2B28DcuJRBvhi9H7fHC1mFLqJIgmMc%3D""
]
And the request body:
array:4 [
"grant_type" => "client_credentials"
"client_id" => "XXXXXXXXXXXX"
"client_secret" => "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
"expires_in" => 87000
]
Sensitive details replaced but consumer_key is correct and thats the same value as client_id and the same goes for consumer_secret and client_secret
No matter how I try and alter the signUsingHmac() method to change the signature, it doesn't work and it all looks fine to me D:
Anyone got any ideas?
If I can get this working nicely I will pull it out into package to make the auth for this API in PHP a lot less painful.
EDIT:
I tried forming the signature exactly like shown in the docs here but to unfortunately it still hasn't worked, this is what my $baseString looked like when passing into the hash method:
POST&https%3A%2F%2Faccount.api.here.com%2Foauth2%2Ftoken&grant_type%3Dclient_credentials%26oauth_consumer_key%3DXXbXbXbXbXbXbXb%26oauth_nonce%3DrZNNSZGOOIHFFtLboCjdAheCmKJmOYSp%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1583640503%26oauth_version%3D1.0
I've also created a new gist here with my updates to create this $baseString
Cheers,
Matt
I created a gist that works.
Some suggestion:
all values need to be urlenconde()
the string that you need to use
for signign the request needs to include: method (uppercase) & URL
(urlecode) & list of parameters (url encoded)
the signing key is your consumer key secret (urlencode) followed by &. This because usually your signing key needs to me consumer secret & secret token. In this case we don't have secret token
For the list of parameters for your signature base string you need to include all oauth_ parameter and your grant_type because you need to include also the body parameter. The sorting of these keys is crucial
some code PHP code:
$keyId = getenv('HERE_API_KEY_ID');
$keySecret = getenv('HERE_API_KEY_SECRET');
$httpBody = [
"grant_type" => "client_credentials"
];
$httpMethod = "POST";
$httpUrl = 'https://account.api.here.com/oauth2/token';
$oauthNonce = mt_rand();
$oauthTimestamp = time();
$oauthSignatureMethod= "HMAC-SHA256";
$oauthVersion = "1.0";
$baseString = $httpMethod."&". urlencode($httpUrl);
$oauth1Param = [
'oauth_consumer_key' => $keyId,
'oauth_signature_method' => $oauthSignatureMethod,
'oauth_timestamp' => $oauthTimestamp,
'oauth_nonce' => $oauthNonce,
'oauth_version' => $oauthVersion
];
$paramString =
"grant_type=client_credentials&".
"oauth_consumer_key=". urlencode($oauth1Param['oauth_consumer_key']).
"&oauth_nonce=". urlencode($oauth1Param['oauth_nonce']).
"&oauth_signature_method=". urlencode($oauth1Param['oauth_signature_method']).
"&oauth_timestamp=". urlencode($oauth1Param['oauth_timestamp']).
// "&oauth_token=".
"&oauth_version=". urlencode($oauth1Param['oauth_version'])
;
echo $paramString.PHP_EOL;
$baseString = $baseString . "&" . urlencode($paramString);
echo $baseString . PHP_EOL;
$signingKey= urlencode($keySecret) . "&";
$signature = urlencode(
base64_encode(
hash_hmac(
'sha256',
$baseString,
$signingKey,
true
)
)
);
$oauth1Param['oauth_signature'] = $signature;
echo "RUNTIME SIGNATURE : " . $signature .PHP_EOL;
I create a GIST that works, the only thing that you need to change is $keyId and $keySecret.
https://gist.github.com/roberto-butti/736c38c796ede70c719f6a21a752c971
This documentation was very useful: https://developer.twitter.com/en/docs/basics/authentication/oauth-1-0a/creating-a-signature
It seems the access_id and access_key both are getting passed in the request body, "grant_type" => "client_credentials" only needs to be in the body, while access_id and access_key should be passed in header. you can try first that in postman, if it does work out, please revert
In a Joomla application I am getting a user info as follows and then I need to save the user info as a contact in a Dynamics 365 database through their REST API.
$user = JFactory::getUser();
$username = $user->username;
$name = $user->name;
I have looked up Dynamics documents around Web API and REST API like this and this, but none of them provide useful info how I can call the API to add a new contact. Currently, I am connecting to Dynamics 365 web application via this url: http://example.com:8088/mysite/api/data/v8.2. The linked post also talks about REST API, but only querying. I'm looking for a way to post data to Dynamics CRM using REST API.
The payload to create Contact using crm webapi will look like this: Read more
POST [Organization URI]/api/data/v8.2/contacts HTTP/1.1
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
"firstname": "Arun",
"lastname": "Vinoth"
}
Sorry am not from PHP background, but this link may help you.
Update:
I browsed little bit. Found the below code sample from SO answer. Update the [Organization URI] with CRM URL, for ex. https://testorg.crm.dynamics.com
$url = '[Organization URI]/api/data/v8.2/contacts';
$data = array('firstname' => 'Arun', 'lastname' => 'Vinoth');
// use key 'http' even if you send the request to https://...
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($data),
),
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
var_dump($result);
I'm using CakePHP and I've already got a access token and a refresh token for the Reddit API, when I make a get request to a endpoint like '/subreddits/popular.json' it works and returns json. My problem is when I make a get request to /subreddits/mine/subscriber.json I get the following response:
302 Found
The resource was found at https://www.reddit.com/subreddits/login.json?dest=https%3A%2F%2Foauth.reddit.com%2Freddits%2Fmine%2Fsubscriber.json%3Fcount%3D100%26limit%3D100; you should be redirected automatically. "
Why is json not returned? or have I missed something the code used to send a get request is:
$endpoint = $this->ENDPOINT_OAUTH . '/subreddits/mine/subscriber.json';
$options = array(
'header' => array(
'Authorization' => $accessToken,
'Accept' => 'application/json',
'Content-Type' => 'application/json; charset=UTF-8'
)
);
$results = $HttpSocket->get($endpoint, $data, $options);
print_r('<pre>');
var_dump($results);
print_r('</pre>');
EDIT: if I add to my options array 'redirect' => true then it redirects to the 302 found url and then returns a 200 ok response but with no data
EDIT 2: After adding the 'redirect' => true I then removed the ':' from in front of Bearer TOKEN and it works
To get it working I needed to add redirect => true to my options parameter so that it sent the second GET request.
When setting my access token it was set like this:
$accessToken = 'Bearer: ' . $accessToken;
When I removed the ':' from the front of Bearer it then worked and returns the results
I have an API that serves Android, IOS and Windows Phone apps. The API works fine with Facebook Graph API. I'm trying to create a method that sends a Facebook notification to user, based on this example and Facebook SDK documentation. Here is my code:
public function sendNotification($uid, $msg, $link){
$postdata = "access_token=$this->access_token&href=$link&template=$msg";
$opts = ['http' => ['method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postdata]];
$context = stream_context_create($opts);
$url = "https://graph.facebook.com/$uid/notifications";
$r = file_get_contents($url, false, $context);
var_dump( $r );
die();
}
My Facebook class has uid, access_token, app_id and app_secret attributes. I should call:
$fb = new Facebook();
$fb->sendNotification($uid, 'Test message', 'http://test.com');
I have the following var_dump:
<b>Warning</b>:
file_get_contents(https://graph.facebook.com/100001795849314/notifications): failed to open stream: HTTP request failed! HTTP/1.1 403 Forbidden in <b>C:\xampp\htdocs\faceteen\api\Classes\Facebook.php</b> on line <b>144</b><br />
bool(false)
I'm running on localhost with Facebook Graph generated token (with manage_notifications perm). I don't want to use Facebook's class, but my own. What am I doing wrong?
I have been trying to implement a simple authentication flow using OAuthv1.a and bit bucket. My issue occurs when I make a request for access tokens using the previously supplied verifier and oauth_token. I am always given a 400 error with no real indication as to why.
Client error response
[status code] 400
[reason phrase] BAD REQUEST
[url] https://bitbucket.org/api/1.0/oauth/access_token?oauth_consumer_key=<snip>&oauth_nonce=fba24cfb3147ca7d32b3924fad43fd509bbb9bc1&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1381034857&oauth_token=fFz369NUmCHNyn7PGj&oauth_verifier=6724267371&oauth_version=1.0&oauth_signature=1H7%2Bvx0fVh2Sj%2FcDAE2QzkTx8us%3D
I am using the OauthPlugin class within guzzle to build signed parameters and submitting post requests as described in the documentation. Has anyone had an issue like this with any other OAuthv1 provider or Bit Bucket specifically?
$client = new Client('https://bitbucket.org/api/1.0/');
$oauth = new OauthPlugin( array(
'request_method' => OauthPlugin::REQUEST_METHOD_QUERY,
'consumer_key' => Config::get('oauthv1.key'),
'token' => Input::get('oauth_token'),
'verifier' => Input::get('oauth_verifier')
)
);
$client->addSubscriber($oauth);
$client->post('oauth/access_token')->send();
Even though the Bitbucket API documentation doesn't mention it, the call to the oauth/access_token endpoint also requires the consumer_secret and oauth_token_secret. The consumer secret is generated by Bitbucket when you create your app and should be stored in your config. You can get the oauth_token_secret from the response of the call to oauth/request_token. Just save it in the session so you can use it when getting the access token.
Request a request token:
$client = new Client('https://bitbucket.org/api/1.0');
$oauth = new OauthPlugin(array(
'consumer_key' => $app['bitbucket.key'],
'consumer_secret' => $app['bitbucket.secret'],
'callback' => 'http://mysite.local/callback',
));
$client->addSubscriber($oauth);
$response = $client->post('oauth/request_token')->send();
// Parse the response
parse_str($response->getBody(), $result);
// Save the token secret in the session
$app['session']->set('oauth_token_secret', $result['oauth_token_secret']);
// Redirect to Bitbucket to authorize the application
return $app->redirect(sprintf('https://bitbucket.org/api/1.0/oauth/authenticate?oauth_token=%s', $result['oauth_token']));
Request an access Token:
$token = $app['request']->get('oauth_token');
$verifier = $app['request']->get('oauth_verifier');
$tokenSecret = $app['session']->get('oauth_token_secret');
$client = new Client('https://bitbucket.org/api/1.0');
$oauth = new OauthPlugin(array(
'consumer_key' => $app['bitbucket.key'],
'consumer_secret' => $app['bitbucket.secret'],
'token' => $token,
'token_secret' => $tokenSecret,
'verifier' => $verifier,
));
$client->addSubscriber($oauth);
$client->post('oauth/access_token')->send();
// Parse the response
$response = parse_str($response->getBody(), $result);
// Get the access token
$accessToken = $result['oauth_token'];