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