frappe / frappe/ecommerce_integrations

Shopify Authentication Error, Support For New Client ID/Secret Auth?

Open
#414 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
207
Forks
276
Avg merge
54m
Merged PRs (30d)
1

Description

Hi all!

I'm trying to install this app to connect my Shopify store to my ERPNext instance, however whenever I try and input credentials that I generated through the Shopify Dev Dashboard I get an authentication error in ERPNext.

Looking through some other issues here, it appears you need to use Legacy Custom Apps to create your Shopify app, however that has been discontinued and users are unable to create legacy apps as of 1/1/2026. So far this integration is completely useless for new users. Are their any plans to support the new client ID/secret authentication used with the new Shopify Dev Dashboard?

Here's the error I'm encountering for reference, it pops up when trying to save the app configuration in ERPNext.

Thanks!

```
### App Versions

{
"ecommerce_integrations": "1.20.2",
"erpnext": "15.97.0",
"frappe": "15.100.0",
"payments": "0.0.1",
"print_designer": "1.0.0-dev",
"webshop": "0.0.1"
}

### Route

Form/Shopify Setting/Shopify Setting

### Traceback

Traceback (most recent call last):
File "env/lib/python3.12/site-packages/pyactiveresource/connection.py", line 286, in _open
http_response = self._handle_error(self._urlopen(request))
^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/pyactiveresource/connection.py", line 316, in _urlopen
return urllib.request.urlopen(request, timeout=self.timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/urllib/request.py", line 215, in urlopen
return opener.open(url, data, timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/urllib/request.py", line 521, in open
response = meth(req, response)
^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/urllib/request.py", line 630, in http_response
response = self.parent.error(
^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/urllib/request.py", line 559, in error
return self._call_chain(*args)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/urllib/request.py", line 492, in _call_chain
result = func(*args)
^^^^^^^^^^^
File "/usr/lib/python3.12/urllib/request.py", line 639, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 401: Unauthorized

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "apps/frappe/frappe/app.py", line 120, in application
response = frappe.api.handle(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/api/__init__.py", line 52, in handle
data = endpoint(**arguments)
^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/api/v1.py", line 40, in handle_rpc_call
return frappe.handler.handle()
^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/handler.py", line 53, in handle
data = execute_cmd(cmd)
^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/handler.py", line 86, in execute_cmd
return frappe.call(method, **frappe.form_dict)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/__init__.py", line 1754, in call
return fn(*args, **newargs)
^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/utils/typing_validations.py", line 32, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/desk/form/save.py", line 39, in savedocs
doc.save()
File "apps/frappe/frappe/model/document.py", line 378, in save
return self._save(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/model/document.py", line 414, in _save
self.run_before_save_methods()
File "apps/frappe/frappe/model/document.py", line 1140, in run_before_save_methods
self.run_method("validate")
File "apps/frappe/frappe/model/document.py", line 1011, in run_method
out = Document.hook(fn)(self, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/model/document.py", line 1371, in composer
return composed(self, method, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/model/document.py", line 1353, in runner
add_to_return_value(self, fn(self, *args, **kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/frappe/frappe/model/document.py", line 1008, in fn
return method_object(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/ecommerce_integrations/ecommerce_integrations/shopify/doctype/shopify_setting/shopify_setting.py", line 45, in validate
self._handle_webhooks()
File "apps/ecommerce_integrations/ecommerce_integrations/shopify/doctype/shopify_setting/shopify_setting.py", line 58, in _handle_webhooks
new_webhooks = connection.register_webhooks(self.shopify_url, self.get_password("password"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "apps/ecommerce_integrations/ecommerce_integrations/shopify/connection.py", line 47, in register_webhooks
unregister_webhooks(shopify_url, password)
File "apps/ecommerce_integrations/ecommerce_integrations/shopify/connection.py", line 69, in unregister_webhooks
for webhook in Webhook.find():
^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/shopify/base.py", line 196, in find
collection = super(ShopifyResource, cls).find(id_=id_, from_=from_, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/pyactiveresource/activeresource.py", line 386, in find
return cls._find_every(from_=from_, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/pyactiveresource/activeresource.py", line 525, in _find_every
response = cls.connection.get(path, cls.headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/pyactiveresource/connection.py", line 329, in get
return self._open('GET', path, headers=headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/shopify/base.py", line 23, in _open
self.response = super(ShopifyConnection, self)._open(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/pyactiveresource/connection.py", line 288, in _open
http_response = self._handle_error(err)
^^^^^^^^^^^^^^^^^^^^^^^
File "env/lib/python3.12/site-packages/pyactiveresource/connection.py", line 415, in _handle_error
raise UnauthorizedAccess(err)
pyactiveresource.connection.UnauthorizedAccess: Response(code=401, body="b'{"errors":"[API] Invalid API key or access token (unrecognized login or wrong password)"}'", headers={'Date': 'Sun, 15 Feb 2026 22:35:00 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'close', 'referrer-policy': 'origin-when-cross-origin', 'x-frame-options': 'DENY', 'x-shopid': '72711110749', 'www-authenticate': 'Basic Realm="Shopify API Authentication"', 'x-request-id': 'f85dcf90-4638-4e75-952c-ef1551503d40-1771194900', 'server-timing': 'processing;dur=20, verdict_flag_enabled;desc="count=3";dur=0.338, _y;desc="5aef595e-5548-4f1d-bf61-e7e891b896aa", _s;desc="cd68d01e-eb54-41f7-9d92-bf0c87607339"', 'content-security-policy': "default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' https://* shopify-pos://*; block-all-mixed-content; child-src 'self' https://* shopify-pos://*; connect-src 'self' wss://* https://*; frame-ancestors 'none'; img-src 'self' data: blob: https:; script-src https://cdn.shopify.com https://cdn.shopifycdn.net https://checkout.pci.shopifyinc.com https://checkout.pci.shopifyinc.com/build/04ed4e1/card_fields.js https://api.stripe.com https://mpsnare.iesnare.com https://appcenter.intuit.com https://www.paypal.com https://js.braintreegateway.com https://c.paypal.com https://maps.googleapis.com https://www.google-analytics.com https://v.shopify.com 'self' 'unsafe-inline' 'unsafe-eval'; upgrade-insecure-requests; report-uri /csp-report?source%5Baction%5D=index&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fwebhooks&source%5Bsection%5D=admin_api&source%5Buuid%5D=f85dcf90-4638-4e75-952c-ef1551503d40-1771194900; report-to shopify-csp", 'x-content-type-options': 'nosniff', 'x-download-options': 'noopen', 'x-permitted-cross-domain-policies': 'none', 'x-xss-protection': '1; mode=block', 'reporting-endpoints': 'shopify-csp="/csp-report?source%5Baction%5D=index&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fwebhooks&source%5Bsection%5D=admin_api&source%5Buuid%5D=f85dcf90-4638-4e75-952c-ef1551503d40-1771194900"', 'x-dc': 'gcp-europe-west1,gcp-us-east1,gcp-us-east1', 'Alt-Svc': 'h3=":443"; ma=86400', 'cf-cache-status': 'DYNAMIC', 'Report-To': '{"endpoints":[{"url":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=9r6do6nlTV%2F8e5FSlQyOATVEPTdDov5utu5H5yePeByMYcW9m48OUsFZ7z23bSCpXgtDkGaidD3OokQT5X9%2FYIFv1miVkgdw3d%2BMta2i98bhpDGIoIXomxYFgNtk%2Bb9r5u9z6PbTcB9D8x4S9TjGBtFcJBAQfZR3kY34s0Q%3D"}],"group":"cf-nel","max_age":604800}', 'NEL': '{"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}', 'Server-Timing': 'processing;dur=20, verdict_flag_enabled;desc="count=3";dur=0.338, _y;desc="5aef595e-5548-4f1d-bf61-e7e891b896aa", _s;desc="cd68d01e-eb54-41f7-9d92-bf0c87607339"', 'Server': 'cloudflare', 'CF-RAY': '9ce8469f087019a9-FRA'}, msg="Unauthorized")

### Request Data

{
"type": "POST",
"args": {
"doc": "{\"name\":\"Shopify Setting\",\"owner\":\"Administrator\",\"modified\":\"2026-02-15 16:54:18.416034\",\"modified_by\":\"Administrator\",\"docstatus\":0,\"idx\":\"0\",\"enable_shopify\":1,\"company\":\"myStore\",\"sync_delivery_note\":0,\"sync_sales_invoice\":1,\"add_shipping_as_item\":0,\"consolidate_taxes\":0,\"upload_erpnext_items\":0,\"update_shopify_item_on_update\":0,\"sync_new_item_as_active\":0,\"upload_variants_as_items\":0,\"update_erpnext_stock_levels_to_shopify\":0,\"inventory_sync_frequency\":\"60\",\"sync_old_orders\":0,\"is_old_data_migrated\":0,\"doctype\":\"Shopify Setting\",\"webhooks\":[],\"taxes\":[{\"docstatus\":0,\"doctype\":\"Shopify Tax Account\",\"name\":\"new-shopify-tax-account-rinqtnznvh\",\"__islocal\":1,\"__unsaved\":1,\"owner\":\"XXX@XXX.com\",\"parent\":\"Shopify Setting\",\"parentfield\":\"taxes\",\"parenttype\":\"Shopify Setting\",\"idx\":1,\"__unedited\":false,\"shopify_tax\":\"Shopify Tax\",\"tax_account\":\"2350 - Shopify Taxes Collected\"}],\"shopify_warehouse_mapping\":[],\"__last_sync_on\":\"2026-02-15T22:26:11.891Z\",\"__unsaved\":1,\"shopify_url\":\"myStore.myshopify.com\",\"password\":\"*****\",\"shared_secret\":\"XXXREDACTEDXXX\",\"default_customer\":\"Guest\",\"customer_group\":\"Shopify\",\"cash_bank_account\":\"XXX\",\"cost_center\":\"Main` \",\"sales_order_series\":\"SAL-ORD-.YYYY.-\",\"sales_invoice_series\":\"ACC-SINV-.YYYY.-\",\"warehouse\":\"XXX\"}",
"action": "Save"
},
"btn": {
"jQuery37008433460285087191": {
"events": {
"click": [
{
"type": "click",
"origType": "click",
"guid": 869,
"namespace": ""
}
]
}
}
},
"freeze": true,
"headers": {},
"error_handlers": {},
"url": "/api/method/frappe.desk.form.save.savedocs",
"request_id": null
}

### Response Data

{
"exception": "pyactiveresource.connection.UnauthorizedAccess: Response(code=401, body=\"b'{\"errors\":\"[API] Invalid API key or access token (unrecognized login or wrong password)\"}'\", headers={'Date': 'Sun, 15 Feb 2026 22:35:00 GMT', 'Content-Type': 'application/json; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'close', 'referrer-policy': 'origin-when-cross-origin', 'x-frame-options': 'DENY', 'x-shopid': '72711110749', 'www-authenticate': 'Basic Realm=\"Shopify API Authentication\"', 'x-request-id': 'f85dcf90-4638-4e75-952c-ef1551503d40-1771194900', 'server-timing': 'processing;dur=20, verdict_flag_enabled;desc=\"count=3\";dur=0.338, _y;desc=\"5aef595e-5548-4f1d-bf61-e7e891b896aa\", _s;desc=\"cd68d01e-eb54-41f7-9d92-bf0c87607339\"', 'content-security-policy': \"default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' https://* shopify-pos://*; block-all-mixed-content; child-src 'self' https://* shopify-pos://*; connect-src 'self' wss://* https://*; frame-ancestors 'none'; img-src 'self' data: blob: https:; script-src https://cdn.shopify.com https://cdn.shopifycdn.net https://checkout.pci.shopifyinc.com https://checkout.pci.shopifyinc.com/build/04ed4e1/card_fields.js https://api.stripe.com https://mpsnare.iesnare.com https://appcenter.intuit.com https://www.paypal.com https://js.braintreegateway.com https://c.paypal.com https://maps.googleapis.com https://www.google-analytics.com https://v.shopify.com 'self' 'unsafe-inline' 'unsafe-eval'; upgrade-insecure-requests; report-uri /csp-report?source%5Baction%5D=index&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fwebhooks&source%5Bsection%5D=admin_api&source%5Buuid%5D=f85dcf90-4638-4e75-952c-ef1551503d40-1771194900; report-to shopify-csp\", 'x-content-type-options': 'nosniff', 'x-download-options': 'noopen', 'x-permitted-cross-domain-policies': 'none', 'x-xss-protection': '1; mode=block', 'reporting-endpoints': 'shopify-csp=\"/csp-report?source%5Baction%5D=index&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fwebhooks&source%5Bsection%5D=admin_api&source%5Buuid%5D=f85dcf90-4638-4e75-952c-ef1551503d40-1771194900\"', 'x-dc': 'gcp-europe-west1,gcp-us-east1,gcp-us-east1', 'Alt-Svc': 'h3=\":443\"; ma=86400', 'cf-cache-status': 'DYNAMIC', 'Report-To': '{\"endpoints\":[{\"url\":\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=9r6do6nlTV%2F8e5FSlQyOATVEPTdDov5utu5H5yePeByMYcW9m48OUsFZ7z23bSCpXgtDkGaidD3OokQT5X9%2FYIFv1miVkgdw3d%2BMta2i98bhpDGIoIXomxYFgNtk%2Bb9r5u9z6PbTcB9D8x4S9TjGBtFcJBAQfZR3kY34s0Q%3D\"}],\"group\":\"cf-nel\",\"max_age\":604800}', 'NEL': '{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}', 'Server-Timing': 'processing;dur=20, verdict_flag_enabled;desc=\"count=3\";dur=0.338, _y;desc=\"5aef595e-5548-4f1d-bf61-e7e891b896aa\", _s;desc=\"cd68d01e-eb54-41f7-9d92-bf0c87607339\"', 'Server': 'cloudflare', 'CF-RAY': '9ce8469f087019a9-FRA'}, msg=\"Unauthorized\")",
"exc_type": "UnauthorizedAccess",
"_exc_source": "ecommerce_integrations (app)"
}
```

_Redacted sensitive information such as shop info and API keys._

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with apps/ecommerce_integrations/ecommerce_integrations/shopify/doctype/shopify_setting/shopify_setting.py, especially validate and _handle_webhooks, then inspect shopify/connection.py and its webhook registration functions. Reproduce the configuration save with the new Shopify credentials and trace the pyactiveresource authentication path. Done means new client ID/secret authentication is supported without the 401 error when saving Shopify settings.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.