I’m writing an app that allows users to integrate their WooCommerce stores with my site. I’m using the Python wrapper for the WooCommerce REST API and my app is hosted on Google App Engine. Here’s my code to call the Woocommerce API. (I’m using https to connect to all the WooCommerce stores)
def request_woo_api(self, user, request_url):
wcapi = API(
url=user.woo_url,
consumer_key=user.woo_consumer_key,
consumer_secret=user.woo_consumer_secret,
wp_api=True,
version="wc/v2",
query_string_auth=True
)
resp = wcapi.get(request_url).json()
return resp
I get a 200 OK response when I test my code on my dev machine. But when I deploy my code to Google App Engine I get a 401 response for some WooCommerce stores.
{u'message': u'Sorry, you cannot list resources.', u'code': u'woocommerce_rest_cannot_view', u'data': {u'status': 401}}
I read here in this documentation that Google App Engine appends a value (AppEngine-Google; (http://code.google.com/appengine; appid: <application_id>)
) to the user-agent
header for all outbound requests. And I think this is the problem because I tried calling a woocommerce api from my local machine and it worked, but when I appended this value to my header the same endpoint gave the 401 error.
>>> headers = {'User-Agent': 'WooCommerce API Client-Python/1.2.1'}
>>> result = requests.get(url, headers=headers)
>>> print result.json()
[{u'date_completed_gmt': None, u'date_modified_gmt': u'2017-11-30T18:13:59', u'payment_method': u'.......
>>> headers = {'User-Agent': 'WooCommerce API Client-Python/1.2.1; AppEngine-Google; (http://code.google.com/appengine; appid: 123)'}
>>> result = requests.get(url, headers=headers)
>>> print result.json()
{u'message': u'Sorry, you cannot list resources.', u'code': u'woocommerce_rest_cannot_view', u'data': {u'status': 401}}
The fact that this happens only for a couple of WooCommerce sites and not the others makes me think that these users might have a WooCommerce setting/plugin extension/security setting that is causing this isssue. Is there any way to-
- Stop GAE from appending to this header to outbound requests?
- Turn off a plugin or setting that prevents the WooCoomerce store from filtering requests based on the
user-agent
value? (I can request the users to change the security settings to their site)
Please help.
( I have already tried the following and it hasn't helped:
- Tried using requests instead of Python wrapper for the WooCommerce REST API and I get the same behaviour; works in local env but returns the 401 error on GAE.
- Added the
query_string_auth=True
and also tried addingverify_ssl=False
(just in case the users were using a self-signed test site) - Tried adding a
_method=GET
query parameter as suggested here - Tried setting the
content-type
to "application/text" as suggested here )
UPDATE
Upon further investigation I found that the WooCommerce store server ignores the query string parameters.
I'm able to get a response if I don’t send the “query_string_auth=true” setting. But the store ignores ALL query parameters. The query_string_auth parameter sends the consumer_key and secret in a query string. When I remove it, it goes as a auth header. Now that I'm sending it as a auth header it responds. But it ignores query parameters. My guess is that the server ignores ALL query parameters. That explains why I was getting the 401 in the first place. (Because we sent the key and secret as a query parameter). And this only happens when I send the "User-Agent: AppEngine-Google;"
Example:
store_url = "https://teststore.com"
endpoint = "/wp-json/wc/v2/orders?per_page=1"
auth = ("ck_xxxxxxxxxxx", "cs_xxxxxxxxxxx")
headers = {'Content-Type': 'application/json', 'User-Agent': 'WooCommerce API Client-Python/1.2.1'}
url = '{}/{}'.format(store_url, endpoint)
response = requests.get(url, auth=auth, headers=headers)
print response.json()
This returns exactly one order.
store_url = "https://teststore.com"
endpoint = "/wp-json/wc/v2/orders?per_page=1"
auth = ("ck_xxxxxxxxxxx", "cs_xxxxxxxxxxx")
headers = {'Content-Type': 'application/json', 'User-Agent': 'WooCommerce API Client-Python/1.2.1; AppEngine-Google; (+http://code.google.com/appengine; appid: 123)'}
url = '{}/{}'.format(store_url, endpoint)
response = requests.get(url, auth=auth, headers=headers)
print response.json()
This returns 10 orders (default page size is 10)
But I still have no idea why some stores do this or how to fix this.