fillup / walmart-partner-api-sdk-php

PHP client for Walmart Partner APIs
MIT License
37 stars 51 forks source link

OAuth and v3 only #77

Open solasus opened 5 years ago

solasus commented 5 years ago

Coming August 28, 2019 - Walmart will be depreciating Digital Signatures and going with oAuth authentication only.

https://developer.walmart.com/#/apicenter/marketPlace/latest#apiAuthentication

Additionally versions 1 & 2 will also be depreciated.

Questions

mjmmagic commented 5 years ago

I hope someone can provide a solution here as well.

I'm NOT a programmer, but I wrote a test PHP file which successfully authenticates with the new Authentication protocol (using the new token method). But I am having trouble integrating that into the existing code.

From what I can see, the authentication (old way) is done in AuthSubscriber.php. However, when I try to change the headers in order to use the new ones, I am getting all kinds of errors.

In other words, this is how the original headers code is written:

$headers = [
            'WM_SVC.NAME' => 'Walmart Marketplace',
            'WM_QOS.CORRELATION_ID' => base64_encode(Random::string(16)),
            'WM_SEC.TIMESTAMP' => $timestamp,
            'WM_SEC.AUTH_SIGNATURE' => $signature,
            'WM_CONSUMER.ID' => $consumerId,
        ];

Notice that doesn't contain the new OAuth parameters for tokens.

So I changed it to the following which contain the new parameters:

$headers = [
        'Authorization: Basic ' => $authorization,
        'WM_SVC.NAME: Walmart Marketplace',
        'WM_SEC.ACCESS_TOKEN: ' => $token,
        'WM_QOS.CORRELATION_ID: ' => base64_encode(Random::string(16)),
        'Host: marketplace.walmartapis.com',
        ];

But that is giving me the following error:

"PHP Fatal error: Uncaught exception 'GuzzleHttp\Exception\ClientException' with message 'Client error response [url] https://marketplace.walmartapis.com/v3/feeds?feedType=inventory [status code] 401 [reason phrase] Unauthorized' in php\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:89"

Since my new headers work in my test program, I assume there is something else I am missing in order to authenticate with Fillup's code.

solasus commented 5 years ago

I'm assuming that you already have a function that goes out and gets a $token (which would be a separate call to the api. These tokens are only valid for 900 seconds (15min).

Also, you may run into problems here because I believe many functions are using v2 of the api. And I'm not sure if it will remain supported or forced to use v3 (current).

That said, I created a some standalone code that just used curl to post to but are using headers like yours. I think the problem you have is that either Host is not correct and/or the array is tripping things up. My array looks like this:
$headers = [ 'Authorization: Basic '.$Client_Auth, 'WM_SVC.NAME: Walmart Marketplace', 'WM_SEC.ACCESS_TOKEN: '.getToken(), 'WM_QOS.CORRELATION_ID: '.generateRandomString(12), 'Host: marketplace.walmartapis.com', 'Content-Type: application/json', 'Accept: application/json', ]; getToken() is my function to generate a new token on each run and generateRandomString(12) is as the name says.

Here's the full code to upload bulk inventory (minus the bits that add to the product info array = $feedData).

`// Walmart defaults $Host = 'https://marketplace.walmartapis.com'; $Client_ID = 'YOUR CLIENT ID'; $Client_Secret = 'YOUR CLIENT SECRET'; $Client_Auth = base64_encode($Client_ID.':'.$Client_Secret);

// random string function generateRandomString($length = 10) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; }

// Get token for Oauth function getToken(){ global $Host, $Client_Auth; $url = $Host.'/v3/token';
$headers = [ 'Authorization: Basic '.$Client_Auth, 'Content-Type: application/x-www-form-urlencoded', 'Accept: application/json', 'WM_SVC.NAME: Walmart Marketplace', 'WM_QOS.CORRELATION_ID: '.generateRandomString(12), 'WM_SVC.VERSION: 1.0.0', 'Host: marketplace.walmartapis.com', ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, 'grant_type=client_credentials'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_ENCODING , ''); $response = curl_exec($ch); if (curl_errno($ch)) { print "Error: " . curl_error($ch); exit(); } curl_close($ch); $json = json_decode($response, true); $access_token = $json['access_token']; return $access_token; }

$feedData = [ 'InventoryHeader' => [ 'version' => '1.4', ], 'Inventory' => $feedData ];

// walmart api if($api == 1) { $data_string = json_encode($feedData); // , JSON_FORCE_OBJECT // echo $data_string; // exit; $url = $Host.'/v3/feeds?feedType=inventory'; $headers = [ 'Authorization: Basic '.$Client_Auth, 'WM_SVC.NAME: Walmart Marketplace', 'WM_SEC.ACCESS_TOKEN: '.getToken(), 'WM_QOS.CORRELATION_ID: '.generateRandomString(12), 'Host: marketplace.walmartapis.com', 'Content-Type: application/json', 'Accept: application/json', ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_ENCODING , '');

$response = curl_exec($ch);
if (curl_errno($ch)) {
    print "Error: " . curl_error($ch);
    exit();
}
curl_close($ch);

print_r($response);
echo '<br><br>';

} `

hope this helps...

solasus commented 5 years ago

... not sure why code didn't format properly, sorry.

mjmmagic commented 5 years ago

That's okay, I appreciate your code and I will give it a shot. It's very similar to what I wrote in my own test PHP file.

Question: is your $feedData in JSON or XML format? I assume JSON based on the header but I'm not a great coder and wanted to double check.

Also, am I correct in saying that you aren't really using the Fillup's method of calling initiating his Client class like this anymore:

$client = new Inventory(
            [
                'consumerId' => CONSUMERID,
                'privateKey' => PRIVATEKEY,
                ],
                Item::ENV_PROD
            );
$feed = $client->bulk([
                'InventoryFeed' => [
                    'InventoryHeader' => [
                        'version' => '1.4',
                    ],
                    'inventory' => 
                        $arrItem,
                ]
            ]);

My original goal (and possibly the original poster on this thread) was to try and just update the few instances in Fillup's code so that it would just authenticate the new way, but still use the old frame work. Oh, and possibly change any instances of v2 to v3 for the new versions.

But it's seeming more like it's not being supported by him anymore, and it might be easier to just rewrite everything in my own functions like you did above for Bulk Inventory uploading. The only functions I really use is Bulk Inventory Update, Import Orders, and Update Prices.

solasus commented 5 years ago

$feedData is a php array that is then json'd by json_encode($feedData)

Yeah - I stared trying to work on this as well - but between battling with guzzle and walmart, I couldn't tell where the problems were originating. So, I opted to just do straight up php code. We only have 4 functions that we need to perform: inventory, get new orders, update shipping info on orders, and refund orders.

mjmmagic commented 5 years ago

You and I sound like we are brothers from another mother! I came to all the same conclusions: that it's too time consuming to decipher all the Guzzle errors, so just start from scratch and code everything on our own. That way, when future changes happen, it's easier to manage without trying to figure out someone else's coding!

I really appreciate your responding to this thread (even though I didn't start it). Hopefully I can reach out to you if I have any other issues, but if not, I wish you the best Solasus!