Kong OSS - 429 does not send Access Control Allow Origin header in response

After implementing rate limiting plugin, say 5 per minute, when I do, I get expected responses:

% repeat 6 { curl -i http://localhost:8100/fake-json/posts }

# 5th and 6th responses shown only
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 225
Connection: keep-alive
X-RateLimit-Limit-Minute: 5
RateLimit-Remaining: 0
RateLimit-Reset: 40
RateLimit-Limit: 5
X-RateLimit-Remaining-Minute: 0
X-Powered-By: Express
Vary: Origin, Accept-Encoding
Access-Control-Allow-Credentials: true
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
X-Content-Type-Options: nosniff
ETag: W/"e1-/STrApA6iIt7ZKpoOQk4lL4vhbM"
Date: Thu, 23 Sep 2021 10:07:20 GMT
X-Kong-Upstream-Latency: 7
X-Kong-Proxy-Latency: 1
Via: kong/2.5.1

[
  {
    "id": 1,
    "title": "json-server",
    "author": "typicode"
  },
  {
    "id": 2,
    "title": "sample post",
    "author": "crnastena"
  },
  {
    "id": 3,
    "title": "mock post",
    "author": "chummie"
  }
]HTTP/1.1 429 Too Many Requests
Date: Thu, 23 Sep 2021 10:07:20 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
X-RateLimit-Limit-Minute: 5
RateLimit-Remaining: 0
RateLimit-Reset: 40
RateLimit-Limit: 5
Retry-After: 40
X-RateLimit-Remaining-Minute: 0
Content-Length: 41
X-Kong-Response-Latency: 0
Server: kong/2.5.1

{
  "message":"API rate limit exceeded"
}

And that is great. But in my sample react app, when I make axios request:

export const getPosts = () => {
  return async (dispatch: Dispatch<GetPostsKnownAction>) => {
    dispatch({
      type: ActionType.GET_POSTS,
    });

    try {
      const response = await axios.get(
        process.env.REACT_APP_API_GATEWAY_URL + '/fake-json/posts'
      );

      console.log("Gateway response:", response);
      const posts:IPost[] = response.data.map((result: any) => {
        return { id: result.id, title: result.title, author: result.author };
      });

      dispatch({
        type: ActionType.GET_POSTS_SUCCESS,
        payload: posts,
      });
    } catch (err: any) {
      console.log("Gateway error:", err)
      dispatch({
        type: ActionType.GET_POSTS_ERROR,
        payload: err.message,
      });
    }
  };
};

axios does not receive the 429 response, rather it throws an error instead.

Access to XMLHttpRequest at ‘http://localhost:8100/fake-json/posts’ from origin ‘http://localhost:3100’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. index.ts:27

And react catch prints this out:

Gateway error: Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:99) xhr.js:187

From what I have been reading online, I would need to configure the server in this instance Kong gateway to send the headers (at least Access-Control-Allow-Origin along with 429 error). Do I understand the problem correctly? Is this something to do with Kong? In essence how can I fix the problem.

Ok, I will answer my own question.

I had to add CORS plugin

apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
  name: fake-json-cors
config: 
  origins:
  - http://localhost:3100
  methods:
  - GET
  - POST
  headers:
  - Accept
  - Accept-Version
  - Content-Length
  - Content-MD5
  - Content-Type
  - Date
  - X-Auth-Token
  exposed_headers:
  - X-Auth-Token
  credentials: true
  max_age: 3600
  preflight_continue: false
plugin: cors

and configure it for the service.

kind: Service
apiVersion: v1
metadata:
  name: proxy-to-fake-json
  annotations:
    konghq.com/plugins: rl-by-ip,fake-json-cors
spec:
  ports:
  - protocol: TCP
    port: 3010
  type: ExternalName
  externalName: host.docker.internal

After this, the 429 contains proper Access-Control- headers.

HTTP/1.1 429 Too Many Requests
Date: Fri, 24 Sep 2021 10:37:27 GMT
Content-Type: application/json; charset=utf-8
Connection: keep-alive
X-RateLimit-Remaining-Minute: 0
X-RateLimit-Limit-Minute: 5
RateLimit-Remaining: 0
RateLimit-Reset: 33
RateLimit-Limit: 5
Retry-After: 33
Content-Length: 41
vary: Origin
Access-Control-Allow-Origin: http://localhost:3100
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Auth-Token
Kong-Request-ID: 3d5a5df3-d4ef-4fc5-bc40-b85ce5b440a3
X-Kong-Response-Latency: 0
Server: kong/2.5.1

{
  "message":"API rate limit exceeded"
}

Back in business.