Repository navigation
Add WooCommerce one-click key behind WOOCOMMERCE_ONE_CLICK (off by default) - #1633
Merged
Merged
Conversation
…fault) The merchant approves a REST API key on their shop (/wc-auth/v1/authorize) instead of pasting one. The unauthenticated callback takes the single-use pending flow, checks the ck_/cs_ shape, answers 200 at once, tries the key on the shop URL stored with the flow through the SSRF guard, and only then writes it through the PUT env-vars path, now shared in connector-env-write.util.ts. Offered only when the flag is true and SERVER_URL is public https; all routes 404 otherwise.
The new controller's WooCommerce tag was missing from the OpenAPI tag list, which failed openapi.spec in CI. A saved shop address that is not public (localhost, private network) now gets its own message instead of "save the address first", and a one-click error (denied, failed, timeout, refused) scrolls into view: it is shown below the key fields and looked as if the click did nothing (#1633).
Contributor
Author
Merged main, fixed CI, tested end to end on a local WooCommerceBranch updates
Checks (in the worktree after the merge)
Manual end-to-end test Setup:
Results, step numbers from the PR description:
The flag stays off by default. Turning it on for Cloud is a separate decision. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds "Connect with one click" to the WooCommerce setup (item L1 of the WooCommerce plan, section 6.2 (A) and 6.3). The merchant approves a REST API key on their own shop through WooCommerce's
/wc-auth/v1/authorizeinstead of creating a key and pasting it. Most WooCommerce setup failures today are key-paste mistakes: the wrong pair, a secret that was not copied, or a key that belongs to a customer-role user.This ships behind a flag that is OFF by default everywhere.
WOOCOMMERCE_ONE_CLICK=trueturns it on. With the flag unset, all three new routes answer 404, the setup page shows no button, and the paste flow works as before. The new endpoint is unauthenticated and receives secrets, and we could not test it end to end on a real store here. Before the flag is turned on for Cloud, it needs an end-to-end test on a real store (procedure below). Matteo approved the authentication change / new credential path on 2026-11-11.How it works
POST /api/woocommerce/connectors/:id/authorizerequires a JWT, the connector's organization, and the connector's owner or an admin (never a VIEWER). It answers 404 unless the flag is on andSERVER_URLis a public https address. The connector must be a WooCommerce connector whose shop address is saved: the setup page saves a draft first. The route stores a pending flow in the existingConnectorOAuthAttemptstore (hashed state, encrypted payload, single use, 15-minute TTL). The flow holds the providerwoocommerce, connectorId, userId, organizationId, the normalised shop URL and the scope (read, the default, orread_write). The route returns<shop>/wc-auth/v1/authorize?app_name=AnythingMCP&scope=…&user_id=<state>&return_url=<FRONTEND_URL>/connectors/setup/woocommerce?connector=<id>&wc=done&callback_url=<SERVER_URL>/api/woocommerce/callback.POST /api/woocommerce/callbackis unauthenticated, throttled to 30 requests a minute, has its own 4 KB body parser mounted before the global one, and answers 404 when the flag is off. It takes the pending flow byuser_id(single use) and checks theck_/cs_patterns. It then records a "working" outcome and answers 200 immediately: WooCommerce deletes the key if this POST fails, and it waits for the answer before it sends the merchant back. Bad body, unknown/expired/used state or a malformed key → 400/410, so WooCommerce deletes the key it just made.GET /wp-json/wc/v3/orders?per_page=1&_fields=id, sent throughassertSafeOutboundUrl+outboundRequest, following no redirects. Only when the shop accepts the key does the server writeWOOCOMMERCE_CONSUMER_KEY/SECRET, through the same code asPUT /api/connectors/:id/env-vars: normalise, field checks, derived settings, rebuild the catalog credentials, reload tools. The write goes to the flow's connector, only if that connector is still in the flow's organization, is still a WooCommerce connector, and still has the same shop URL. Nothing else from the body is used.GET /api/woocommerce/connectors/:id/one-click-status?state=<user_id>(JWT, same organization, same user) every 2 seconds for up to 60 seconds. The result ispending,working,ready(success screen) orfailedwith the reason, for example "its WordPress user may not see orders", a firewall, a 404 or permalinks set to Plain.success=0means the merchant did not approve, and the page says so.The callback never logs the body, the key or the secret. Log lines name only the connector id and a failure kind. Errors are logged by name, not message, and verification messages never quote the key.
Changes
connectors/woocommerce-auth.controller.ts(new): the three routes plusGET /api/woocommerce/one-click, which tells the frontend whether to show the button (same pattern asGET /api/tiktok-shop/platform). Also the helpers it needs: the flag/reachability gate, shop URL normalisation, key verification, the callback body parser, and DTOs. The callback body is validated with class-validator by hand, withoutforbidNonWhitelisted, so a field WooCommerce adds later cannot make it delete the key.connectors/connector-env-write.util.ts(new): the body ofPUT /api/connectors/:id/env-varsand its helpers, moved here unchanged so the callback writes through exactly the same path.ConnectorsControllernow delegates to it, and its behaviour is unchanged (all 107 connectors spec suites pass).connectors/oauth1-consumer-key.util.ts(new):looksLikeEmail/assertConsumerKeyIsNotEmailmoved out of the controller to avoid a circular import. The controller still re-exports them.connectors/mcp-oauth.service.ts: the provider union gainswoocommerce/woocommerce-outcome, plus an optionalwoocommercepayload field. No Prisma schema change.main.ts: the 4 KB parser for/api/woocommerce/callback.connectors.module.ts: registers the controller.WooCommerceOneClickpanel offers Read only (recommended) or Read and write, with the paste fields kept below as the fallback. It shows on the key step of the guide and above the key fields in the one-page form, only when the backend reports the feature available. The page also handles the return and polls for the outcome. Strings are inconnectorSetup.wooOneClick(en, de, it), following the setup page's next-intl pattern..env.example,docs/deployment.md(env table), anddocker-compose.yml/docker-compose.cloud.ymlpassWOOCOMMERCE_ONE_CLICKthrough, defaulting to empty, which means off.ee/.adapters/intl/woocommerce.jsonis not touched (Auto-apply catalog updates that only add optional query parameters; WooCommerce sync filters #1631 and the guided-setup branch edit it).Cloud vs self-hosted
The behaviour is the same in both modes and keyed only on the flag and
SERVER_URL:trueandSERVER_URLa public https address (Cloud): button shown.trueandSERVER_URLhttp, localhost, a private IP or a single-label host (a typical self-hosted LAN install): button hidden and routes 404, because WooCommerce'swp_safe_remote_postcannot reach such a callback.Type
Testing
packages/backend/src/connectors/woocommerce-auth.controller.spec.tshas 50 tests. They cover:truestays offSERVER_URLhides the button and gives 404authConfigand reloading toolsverifyWooCommerceKeyCommands run locally:
packages/backend:npm run lint→ 0 errors (11 existing warnings, none in changed files); the diff after--fixwas reviewed and has no unintended changes.packages/backend:npx tsc --noEmit -p tsconfig.json→ no errors in changed files. The only errors are the existing local ones from modules not installed in this checkout (@aws-sdk/client-s3,picomatchtypes,ssh2,basic-ftp).packages/backend:npx jest src/connectors src/adapters --maxWorkers=4, with a local jest config that only stubs those missing modules → 845 suites passed, 3 skipped; 28,197 tests passed, 1,878 skipped; 0 failures (the new spec: 50/50).packages/frontend:npm run lint→ 0 errors (54 existing warnings, none in changed files);npx tsc --noEmit -p tsconfig.json→ clean.Manual end-to-end test on a real store (required before enabling on Cloud)
Prerequisites: a WordPress + WooCommerce store on https with pretty permalinks, an administrator login, and an AnythingMCP backend reachable from the internet over https (
SERVER_URL=https://…, for example a staging droplet) withWOOCOMMERCE_ONE_CLICK=true.GET /api/woocommerce/one-clickwhile signed in →{"available": true}./connectors/setup/woocommerce, enter the shop address, and go to "Create a REST API key". The "Connect with one click" panel shows. Keep Read only, then click it.<shop>/wc-auth/v1/authorize?.... Sign in to WordPress if asked and click Approve./connectors/setup/woocommerce?connector=…&wc=done&success=1&user_id=…. The page shows "Checking the new key with your shop…", then the success screen.woocommerce_list_orders {per_page:1}works; in WP admin, WooCommerce → Settings → Advanced → REST API lists "AnythingMCP - API (Read)" with Read permission. Repeat with Read and write and check that a write tool works.WooCommerce one-click key (read) stored for connector <id>, and no key or secret anywhere (grep ck_ / cs_on the logs).(a) Click Deny → back with
success=0and the "not approved" message.(b) Approve while signed in as a WordPress user without
manage_woocommerce→ "failed" with the shop manager hint, and nothing written.(c) Replay the same callback with curl → 410.
(d) Send a callback body over 4 KB → 413.
(e) Wait more than 15 minutes on the Approve screen, then approve → WooCommerce shows its error, and the key is deleted on the shop side.
(f) With Wordfence on default rules and with Cloudflare in front: check whether
/wc-auth/and the callback get through.(g) Plain permalinks: the authorize link 404s (expected; the paste flow remains).
(h) Set
WOOCOMMERCE_ONE_CLICKunset → button gone, all routes 404.Checklist
npm test): run in CI; locally the connectors and adapters suitesRelated Issues
WooCommerce plan, item L1 (sections 6.2 (A), 6.3, 8.4). Auth change approved by Matteo on 2026-11-11.