Skip to content
  1. Extras
  2. MiniShop3
  3. Development
  4. Web API
  5. CORS and rate limit

CORS and rate limit ​

Settings in namespace minishop3: System settings → API.

CORS ​

ms3_cors_allowed_origins valueBehavior
empty (this is what the installer writes)Same-origin only: CORS headers are not set
*Access-Control-Allow-Origin: *, credentials are turned off
comma-separated listThe server echoes the request Origin and adds Vary: Origin and Allow-Credentials: true

web.php creates CorsMiddleware with allow_credentials => true.

Allowed methods: GET, POST, PUT, DELETE, OPTIONS. Allowed headers: Content-Type, Authorization, X-Requested-With, MS3TOKEN. max_age is 86400.

In a pattern such as https://*.example.com the asterisk replaces one DNS label, not an arbitrary part of the address.

OPTIONS preflight returns 200 without token mint.

Rate limit ​

Over the quota:

http
HTTP/1.1 429 Too Many Requests
Retry-After: 42
json
{
  "success": false,
  "message": "ms3_err_rate_limit",
  "code": 429,
  "errors": null,
  "error_code": "rate_limited"
}

The window is fixed: it starts with the first request, reset_at is set once as «now plus ms3_rate_limit_decay_seconds» and never slides. Once the window is over, the counter resets completely.

HeaderWhen it is sentWhat it holds
Retry-Afterwith a 429 onlyseconds until the window ends
X-RateLimit-Limitwhile the request fits the quotathe value of ms3_rate_limit_max_attempts
X-RateLimit-Remainingthe samehow many requests are left
X-RateLimit-Resetthe samea Unix timestamp of the window end, not a number of seconds

Behind a reverse proxy the counter is shared

The bucket key is md5() of REMOTE_ADDR. The middleware deliberately ignores headers such as X-Forwarded-For: the client controls them, so the limit could be bypassed by forging one. If the site sits behind a reverse proxy, a CDN or a Nuxt server and the web server does not replace REMOTE_ADDR with the visitor address, every customer shares one bucket and hits a common limit. Configure the real address at the web-server level.

OPTIONS requests do not consume the quota.

SettingDefaultWhat it sets
ms3_rate_limit_max_attempts60Number of requests in the window
ms3_rate_limit_decay_seconds60Window length in seconds

ms3_rate_limit_store picks the counter storage (default file). The installer also creates the redis and memcached keys and the file path next to it. The error body is described in Errors.

An environment variable overrides the setting, and a backend failure is silent

When the MS3_RATE_LIMIT_STORE environment variable is set, its value wins and the system setting is ignored.

When the chosen backend is unavailable — no redis or memcached extension, or the connection fails — the factory writes a WARN to the log and quietly falls back to file storage. Requests keep working, but on a cluster the counter stops being shared: every node starts counting its own attempts. Check the log after changing the storage.

Nuxt on another origin ​

  1. List the frontend origin (or BFF) in ms3_cors_allowed_origins.
  2. Requests with credentials: 'include' or Bearer without cookie.
  3. Do not set * together with a cookie session: with that value a cookie from another origin will not work.