kraftware / sw6-store-api-captcha
Enforce Shopware core captchas on Store API routes
Package info
github.com/runelaenen/sw6-store-api-captcha
Type:shopware-platform-plugin
pkg:composer/kraftware/sw6-store-api-captcha
Requires
- php: ^8.2
- shopware/core: ^6.7
- shopware/storefront: ^6.7
README
Enforce Shopware's core captchas on Store API routes. Shopware only enforces captchas on Storefront routes out of the box; this plugin extends the same captcha framework to the Store API, which is useful for headless / composable frontends and API integrations.
No new captcha type is added. The plugin reuses the captchas registered under the
shopware.storefront.captcha tag (Honeypot, Google reCAPTCHA v2/v3, and any third-party
captcha such as Cloudflare Turnstile) and the captcha selection configured under
Settings → Basic information.
How a route gets protected
A Store API route is protected when either:
-
It declares the
_captcharoute attribute — parity with how Storefront routes opt in. Plugin authors adddefaults={"_captcha"=true}(or the attribute equivalent) to their own Store API route. Example:#[Route(path: '/store-api/my-route', name: 'store-api.my-route', defaults: ['_captcha' => true], methods: ['POST'])]
-
Its route name is listed in the plugin configuration — open the plugin config and add one Store API route name per line, e.g.:
store-api.account.register store-api.contact.formUse mechanism 2 to protect existing core or third-party routes without changing their code.
Matching is by exact route name (the Symfony _route).
Behaviour
- Runs only for requests in the
store-apiroute scope; Storefront and Admin API behaviour is untouched. - On captcha failure the request is rejected with the core
CaptchaException: HTTP 403, error codeFRAMEWORK__INVALID_CAPTCHA_VALUE, as a Store API JSON error. - On success the request proceeds normally.
- Honors per-sales-channel configuration for both the route list and the captcha selection.
- Only POST requests are validated. The core captchas apply to form/POST submissions and
return
supports() === falsefor other methods. GET requests are never captcha-checked, so protect state-changing POST routes. Adding a GET-only (or GET-served) route to the list does not captcha-protect its GET traffic.
Client responsibility
This plugin only validates. The API client must obtain the captcha token and send the
captcha parameter in the request body, e.g. _grecaptcha_v3 for Google reCAPTCHA v3. Captcha
parameters sent in a JSON body are read correctly (Shopware decodes the JSON body into the
request parameters before validation).
Notes and limitations
- Storefront bundle required. The captcha implementations live in
shopware/storefront, which is a hard dependency. A pure headless install without the Storefront bundle is not supported. - Token-based captchas recommended. Google reCAPTCHA v2/v3 (and other token-verified captchas) are stateless and work well over the Store API.
- BasicCaptcha is skipped, not enforced. The image-based BasicCaptcha reports
shouldBreak() === falsebecause it expects an interactive image/session challenge that cannot be presented to a stateless API client. Rather than hard-block every request, the plugin skips any active captcha whoseshouldBreak()isfalse. Do not rely on BasicCaptcha for Store API protection. - Honeypot is weak on a headless client. Honeypot treats an empty field as valid, which works against bots that blindly fill hidden form fields. A first-party API client simply never sends the field, so honeypot passes every request and provides little real protection over the Store API. Prefer a token-verified captcha.