5

Does anyone have python code that can generate this header for the Walmart API?

WM_SEC.AUTH_SIGNATURE

I have tried to wrap my head around the java example but I am not having any luck of it as I have no Java experience.

If anyone knows the format of the string that needs to be signed I could probably figure it out from there.

How do I solve the problem?

Emma
  • 27,428
  • 11
  • 44
  • 69
plugcity
  • 113
  • 1
  • 7

4 Answers4

4

Here is the code that I ended up using to get the authorization to work if anyone needs it:

import requests, json, pprint, time
from requests.auth import HTTPBasicAuth
import errno
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
import hashlib
import base64


ACCOUNT_SID = 'xxxxxx'
AUTH_TOKEN = 'xxxxxxxx'
BASE_URL = 'https://products.api.impactradius.com/Mediapartners/{}/'.format(ACCOUNT_SID)
API_PATH = 'Catalogs/4277'
consumerId = 'xxxxxxxx'
epoxTime = str(int(time.time()*1000))
keyVersion = '1'

URL = 'https://developer.api.walmart.com/api-proxy/service/affil/product/v2/items'


hashDict = { 'WM_CONSUMER.ID' : consumerId,
            'WM_CONSUMER.INTIMESTAMP' : epoxTime,
            'WM_SEC.KEY_VERSION' : keyVersion
            }
sortedHashString = hashDict['WM_CONSUMER.ID'] +'\n'+ hashDict['WM_CONSUMER.INTIMESTAMP'] +'\n'+ hashDict['WM_SEC.KEY_VERSION']+'\n'
encodedHashString = sortedHashString.encode()

try:
    with open('./WM_IO_private_key.pem', 'r') as f:
        key = RSA.importKey(f.read())
except IOError as e:
    print(e)

hasher = SHA256.new(encodedHashString)
signer = PKCS1_v1_5.new(key)
signature = signer.sign(hasher)

signature_enc = str(base64.b64encode(signature),'utf-8')

headers = { 'WM_CONSUMER.ID' : consumerId,
            'WM_CONSUMER.INTIMESTAMP' : epoxTime,
            'WM_SEC.AUTH_SIGNATURE' : signature_enc,
            'WM_SEC.KEY_VERSION' : keyVersion,
            'WM_QOS.CORRELATION_ID' : 'afjksldkfj4r8ojfns',
            'WM_IFX.CLIENT_TYPE' : 'INTERNAL',
            'WM_PREVIEW' : 'false',
            'WM_SHOW_REASON_CODES' : 'ALL',
            'Content-Type' : 'application/json',
            }

params = {
            'category' : '4171_1228385',
            'publisherId' : 'xxxxxxxxxxx'
        }

response = requests.get(URL, headers=headers, params=params)

jsonData = json.loads(response.text)
plugcity
  • 113
  • 1
  • 7
2

Be aware that this method of Authentication will no longer work soon.

We are deprecating Digital Signature-based Authentication (Consumer ID and Private Key) on August 28, 2019. If you are currently using this method, your API calls will not work after August 28, 2019.

But if you still wish to try it:

From the API documentation

To get the digital signature using your own code, follow these steps:

  1. Get the Consumer ID and your Base 64-encoded Private Key you generated in Seller Center.
  2. Get the full URL you wish to call, including any path and query parameters.
  3. Use the GET method to construct an input for the digital signature.
  4. Use the structure listed below:
  • The Consumer ID issued to you_ + "\n" +
  • the URL of the API call you are making + "\n" +
  • the request method of the API call you are making in all capitals + "\n" +
  • the Unix Epoch timestamp now (in milliseconds since Jan 01 1970 UTC) + "\n"

** Note: The order of the parameters and the line returns \n are important to generate the signature properly

  1. Generate the byte array of the structured data listed in step 3 using the following steps: a. Decode the byte array with Base-64.

    b. Encode the resulting value using PKCS#8 to represent your Private Key. Libraries in various languages offer the ability to identify that the Private Key is in PKCS#8 format and not in other conflicting formats such as PKCS#1. c. Use this byte representation of your private key to sign the data using SHA-256 with RSA. d. Encode the generated digital signature using Base-64.

  2. Use the generated digital signature and the timestamp to make your API call.

toastifer
  • 478
  • 3
  • 8
  • 1
    Thanks for this. I was actually trying to use it for the Affiliates API. This helped me see that I needed to add a "\n" to the final parameter. I am now able to make successful calls to the affiliates API. Is the affiliates API deprecating Digital Signature-based Authentication as well on August 28? – plugcity Aug 07 '19 at 21:35
  • I haven't been able to find any information one way or another. – toastifer Aug 08 '19 at 11:12
  • ya same here. seems like the Affiliates API is a forgotten resource. The little documentation there is for it seems to have a lot of holes in it. – plugcity Aug 08 '19 at 14:55
  • well, same here. And the Affiliates API docs do not anywhere mention this. hey @plugcity can I ask u a quick question, what is the value of "WM_SEC.KEY_VERSION" that you use in your code? – codeFood Aug 25 '19 at 23:05
  • 1
    Is this still working with the Affiliates API? I saw this method is deprecated in the Marketplace API but can't seem to find anything about the Affiliates. (https://developer.walmart.com/#/apicenter/marketPlace/latest#apiAuthentication) – mikemike396 Oct 08 '19 at 20:23
  • Does it say what it's replacing this authentication with? – Joe Morano Jun 09 '20 at 00:07
  • "The Walmart Marketplace APIs use OAuth for token-based authentication and authorization. This is the new standard method which should be used moving forward." – toastifer Jun 09 '20 at 14:34
2

Below example for Affiliates API on PHP

String (message) for sign

$message = self::WM_CONSUMER_ID . "\n" . $milliseconds . "\n" . self::WM_SEC_KEY_VERSION . "\n";

PHP Example class

<?php

declare(strict_types=1);

namespace WalmartBundle\Services;


use phpseclib\Crypt\RSA;

/**
 * Class WalmartAuthSignature
 *
 *  Thanks: https://github.com/fillup/walmart-auth-signature-php/blob/develop/src/Signature.php
 *
 * @package WalmartBundle\Services
 */
class WalmartAuthSignature
{
    public static function sign(string $message, string $privateKey): string
    {
        $rsa = new RSA();

        $decodedPrivateKey = base64_decode($privateKey);
        $rsa->setPrivateKeyFormat(RSA::PRIVATE_FORMAT_PKCS8);
        $rsa->setPublicKeyFormat(RSA::PRIVATE_FORMAT_PKCS8);

        if ($rsa->loadKey($decodedPrivateKey, RSA::PRIVATE_FORMAT_PKCS8)) {
            $rsa->setHash('sha256');
            $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1);
            $signed = $rsa->sign($message);

            return base64_encode($signed);
        }

        throw new \Exception('Unable to load private key');
    }
}
0

As of today, auth signature code is available in Java (https://www.walmart.io/docs/affiliate/onboarding-guide)   The idea we provided sample code to help the customers to implement the logic at customer end by referring it You can implement the logic in(.NET, Python, PHP or JS) in such a way that whenever your system invoking Walmart APIs, generate the signature on the fly and pass as input parameter   This is how all of customers implemented and consuming our APIs   Pls refer the below documentation for complete. https://walmart.io/docs/affiliate/quick-start-guide https://www.walmart.io/docs/affiliate/onboarding-guide   Regards, Firdos IO Support