Rate Limit (429) and CORS

I have implemented my own Rate Limit in SS.
However, as the service itself is called from a SPA with CORS enabled, the actual Http Error 429 is not passed through to the SPA, instead I get the CORS error

Access to fetch at 'https://(webapi)/json/reply/XXXX' from origin '(website)' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.

Is there a way to avoid this? So that instead of the CORS policy error, I can provide the 429?

If I use the API call directly I do get the 429 as expected.

What does your CorsFeature configuration look like? Can you also post the full HTTP Request/Headers causing that error.

Please note that CORS is working fine for the calls I don’t attribute with RateLimit.

This is my CorsFeature settings:

Plugins.Add(new CorsFeature(
					allowOriginWhitelist: urlWhiteList,
					allowCredentials: true,
					allowedHeaders: "Content-Type, Allow, Authorization"));

Request headers:

POST /json/reply/BotProcessAnonymousMessage HTTP/1.1
Host: localhost:5000
Connection: keep-alive
Content-Length: 34
Sec-Fetch-Dest: empty
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
content-type: application/json
Accept: */*
Origin: http://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Referer: http://localhost:3000/direct/CONFIRTFN
Accept-Encoding: gzip, deflate, br
Accept-Language: en,nl;q=0.9

Response Headers

HTTP/1.1 429 Too many Requests. Back-off and try again later.
Date: Sat, 21 Mar 2020 11:17:44 GMT
Content-Length: 0
Access-Control-Allow-Origin: http://localhost:3000

In my console

Access to fetch at 'http://localhost:5000/json/reply/BotProcessAnonymousMessage' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
index.js?7626:829 POST http://localhost:5000/json/reply/BotProcessAnonymousMessage net::ERR_FAILED

And the try catch in my vue app gives this as ‘error’

TypeError: Failed to fetch

So basically the ServiceStack call is fine, gives me the 429.
However, the browser, (and the ServiceStack JsonClient), seems to “see” the CORS issue as the root cause.

Is that the full Response Headers? It’s missing the main Global CORS Headers, can you show the code that’s writing the 429 Response?

I have added a plugin that adds a GlobalRequestFilters; based upon an attribute on the service I do some checking; if the limit is exceeded I do:

response.StatusCode = 429;
response.StatusDescription = "Too many Requests. Back-off and try again later.";
response.Close();

This is all I get in the google chrome dev tools when calling the service:

That’s why it’s not writing the Global Response Headers, use EndRequest() to short-circuit the response.

YES. That did it. Thanks for your great support!

1 Like