Can't get CORS config to work

571 views
Skip to first unread message

Jörg Erdmenger

unread,
Jun 26, 2023, 1:14:44 PM6/26/23
to comm...@krakend.io
Hi all,

I'm having trouble getting krakend to send CORS headers. I configured krakend according to the example at https://www.krakend.io/docs/service-settings/cors/ with carefully adding all headers I'm observing that my browser sends e.g.:

"security/cors": {
"allow_origins": [
],
"allow_methods": [
"GET",
"POST",
"HEAD",
"OPTIONS"
],
"expose_headers": [
"Content-Length",
"Content-Type"
],
"allow_headers": [
"Accept",
"Authorization",
"Accept-Language",
"Accept-Encoding",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Origin",
"Content-Type",
"Cache-Control",
"Pragma",
"Host",
"User-Agent",
"Connection",
"Referer",
"Sec-Fetch-Dest",
"Sec-Fetch-Mode",
"Sec-Fetch-Site"
],
"max_age": "12h",
"allow_credentials": false,
"debug": true
}

My SPA now makes an OPTIONS request before it makes the GET request which fails with a CORS error because
the Access-Control-Allow-Origin header is missing and as far as I can tell from the browser network console
this header is not sent. In the krakend logs I get many debug logs like that:

[KRAKEND] 2023/06/26 - 17:12:56.140 ▶ DEBUG [CORS] 2023/06/26 17:12:56 Handler: Actual requesters added: missing origin
[KRAKEND] 2023/06/26 - 17:12:56.140 ▶ DEBUG [CORS] 2023/06/26 17:12:56 Actual request no headers added: missing origin

Can anybody shed some light on this or am I missing something?

Thanks

Jörg

Albert Lombarte

unread,
Jun 27, 2023, 2:35:45 AM6/27/23
to KrakenD Community, jo...@woerd.org
Hi Jörg,

The issue you have is not with cors, but with the OPTIONS. Add the following option to the configuration and you should good to go:

El dia dilluns, 26 de juny de 2023 a les 19:14:44 UTC+2, jo...@woerd.org va escriure:

Jörg Erdmenger

unread,
Jun 27, 2023, 7:04:09 AM6/27/23
to comm...@krakend.io
Hi Alberto,

thanks for the quick reply - I wasn't aware of the auto_options config option. Unfortunately it hasn't solved my problem which seems to be the combination of pre-flight requests with the necessity of the endpoint I'm gatewaying to require a JWT authorization header. It seems that the browser when crafting the pre-flight OPTIONS call doesn't include the authorization header (that it will include in the actual GET request and therefor the OPTIONS call responds with a 302 status to initiate an oauth flow.
Is there some other setting I have overlooked that would make krakend respond to the OPTIONS call with the configured access-control-allow-origin header even if the authorization header that the backend of the actual request required is missing?

Thanks

Jörg

David Hontecillas

unread,
Jun 27, 2023, 8:33:25 AM6/27/23
to KrakenD Community, jo...@woerd.org
Hey Jörgo,

perhaps this enterprise feature is what you are looking for ? https://www.krakend.io/docs/enterprise/backends/client-redirect/ ? Or I might be misunderstanding your issue.

Jörg Erdmenger

unread,
Jun 27, 2023, 8:42:29 AM6/27/23
to David Hontecillas, KrakenD Community
I don't think that would solve the issue if I understand what is going on. From what I understand the browser doesn't include the authorization header in the pre-flight request (but would include it in the actual request) - what the desired behaviour from my point of view would be is that if krakend received an preflight OPTIONS request it would just return the configured allow-origin headers without even hitting the backend and then the browser would call the actual endpoint with an actual GET request and because on that request it would send the authorization header that would work.
From looking at the documentation I thought I understood that by specifying allow_credentials: true the CORS logic would work as expected even when a request would include tokens, auth, certs etc. and the auto_options: true option would configure an OPTIONS endpoint for each configured endpoint so that the pre-flight requests would succeed. Can I find out in a bit more detail what exactly the expected functionality of the allow_credentials and auto_options is?

jörg

Jörg Erdmenger

unread,
Jun 29, 2023, 5:03:57 AM6/29/23
to KrakenD Community
Hi KrakenD community,

I don't want to be too pushy but I'm really looking for some advice on this CORS problem where an xhr call with an Authorization header bearing a JWT token fails because the browser considers requests with Authorization header not simple and therefor pre-flights them with an OPTIONS call. This OPTIONS call doesn't include the Authorization header and therefore is responded with an 302 to initiate an oauth flow. My expectation would be that this OPTIONS request to krakend would just trigger a response with the  Access-Control-Allow-Origin header as configured by the allow_origins directive of the krakend configuration. As suggested by the people on the mailing list I added the auto_options: true directive to my config but that hasn't changed the behaviour and now I'm trying to understand what exactly that directive does and whether this should actually do what I want or whether I'm just on the wrong way. I'd be happy to go to the source to educate myself (even though my go is minimal) - a pointer to a good starting point would be appreciated.

jörg

Daniel Lopez

unread,
Jun 29, 2023, 10:02:27 AM6/29/23
to Jörg Erdmenger, KrakenD Community
Hi, Jörg

I think there is something in your stack that makes that behavior. Can you share your endpoint configuration? The thing is, neither the CORS nor the JWT layers in krakend return a 302, so I think it may come from your backend

Best

--
You received this message because you are subscribed to the Google Groups "KrakenD Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to community+...@krakend.io.
To view this discussion on the web visit https://groups.google.com/a/krakend.io/d/msgid/community/CABO1FMQfpyE%2B1g%3D9uiXOSA%3De6znsoUV8Kpj%3D3t8nVdC5Mp%2Bu5w%40mail.gmail.com.


--
Logo
Daniel López
CTO

LinkedIn icon   Twitter icon  

Confidentiality Notice: This email, including any attachments, may contain confidential and privileged information for the sole use of the intended recipient(s). Any unauthorized review, use, disclosure, or distribution is prohibited. If you are not the intended recipient, please contact the sender immediately and destroy all copies of this email. Thank you. This email has been sent in accordance with the European Union General Data Protection Regulation (EU GDPR).

Jörg Erdmenger

unread,
Jun 30, 2023, 7:49:21 AM6/30/23
to KrakenD Community
Hi,

yes I'm happy to share the config - see attached file. The endpoint I'm testing with is that one:

{
            "endpoint": "/dwapp/krakend/api/v1/customers/-/find",
            "output_encoding": "json",
            "method": "GET",
            "backend": [{
                "encoding": "json",
                "url_pattern": "/api/v1/customers/-/find",
                "method": "GET",
                "host": [
                    "https://k5-dwapp-customer.banking-solutions-dev.svc"
                ],
                "extra_config": {
                    "modifier/martian": {
                        "header.Blacklist": {
                            "scope": ["request"],
                            "names": ["Access-Control-Request-Method", "Origin", "Sec-Fetch-Dest", "Sec-Fetch-Mode", "Sec-Fetch-Site", "Access-Control-Request-Header", "Access-Control-Request-Method"]
                        }
                    }
                }
            }],
            "input_headers": [
                "Authorization",
                "Content-Type",
               etc...
            ],
            "input_query_strings": [
                "name",
                "includeHistory",
                etc...
            ]
        }

The backend is a service that is expecting an Authorization header and that I guess will respond with a 302 when not being presented with a valid token. So what I'm trying to understand is what the expected behaviour of krakend would be. If I have the auto_options enabled and the OPTIONS endpoint is not explicitly configured, should krakend even call the backend when it receives an OPTIONS request? Would the expectation not be that it just reponds with the configured allowed origins when CORS is enabled? Or am I missing something?

Thanks

Jörg
krakend-config.json

Jörg Erdmenger

unread,
Jul 6, 2023, 3:13:35 AM7/6/23
to KrakenD Community, dlo...@krakend.io
Hi again,

I'm still struggling with this issue and I really am stuck with what I'm doing wrong. I'm happy to further educate myself if someone could give me some more pointers. I'd also like to understand what I should rightfully expect from the out-of-the box CORS functionality and whether the reason I'm having these problems is that I just expect too much "magic" happening automatically, but the docs are a bit vague there...

Thanks

jörg
krakend-config.json

Albert Lombarte

unread,
Jul 7, 2023, 5:11:35 AM7/7/23
to KrakenD Community, jo...@woerd.org, Daniel Lopez
Hi Jörg,

The auto_options in the router section enables the OPTION method for all registered endpoints in the gateway. It is completely unrelated to the CORS configuration. When using auto_options, the gateway does not call or involve any backend when used, as it simply returns an "allow" header with the supported methods. For instance:

$ curl -XOPTIONS -i http://localhost:8080/test HTTP/1.1 200 OK Allow: DELETE, GET X-Krakend: Version 2.3.2-ee Date: Fri, 07 Jul 2023 08:52:05 GMT Content-Length: 0

The backend has not been called.

Now to the CORS part. When you enable the CORS middleware (I am using your configuration), if the client does not set any CORS-related headers (i.e. Origin or Access-Control-Request-Method) it keeps having the same output as before and CORS does not trigger:

$ curl -XOPTIONS -i http://localhost:8080/test HTTP/1.1 200 OK Allow: DELETE, GET X-Krakend: Version 2.3.2-ee Date: Fri, 07 Jul 2023 08:52:05 GMT Content-Length: 0

When you pass CORS header, such as the header Access-Control-Request-Method, CORS is triggered, and you can see the Vary header added by the CORS middleware:

$ curl -H'Access-Control-Request-Method: GET' -XOPTIONS -i http://localhost:8080/test HTTP/1.1 204 No Content Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Date: Fri, 07 Jul 2023 08:55:49 GMT

And you can see in the KrakenD logs in this case:

2023/07/07 08:57:09 KRAKEND DEBUG: [CORS] 2023/07/07 08:57:09 Handler: Preflight request origin missing origin

As you can see, the origin is missing in our previous test. Let's add it:

$ curl -H'Origin: http://localhost:8080' -H'Access-Control-Request-Method: GET' -XOPTIONS -i http://localhost:8080/test HTTP/1.1 204 No Content Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET Access-Control-Allow-Origin: http://localhost:8080 Access-Control-Max-Age: 43200 Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Date: Fri, 07 Jul 2023 08:58:04 GMT

And now you see in the KrakenD logs:

2023/07/07 08:58:25 KRAKEND DEBUG: [CORS] 2023/07/07 08:58:25 Handler: Preflight request s: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Methods:[GET] Access-Control-Allow-Origin:[http://localhost:8080] Access-Control-Max-Age:[43200] Vary:[Origin Access-Control-Request-Method Access-Control-Request-Headers]] 2023/07/07 08:58:25 KRAKEND DEBUG: [CORS] 2023/07/07 08:58:25 Preflight response headers: map[Access-Control-Allow-Credentials:[true] Access-Control-Allow-Methods:[GET] Access-Control-Allow-Origin:[http://localhost:8080] Access-Control-Max-Age:[43200] Vary:[Origin Access-Control-Request-Method Access-Control-Request-Headers]]

CORS is working.

To better understand the flow, you can have a look at the source code of the component: https://github.com/rs/cors/blob/master/cors.go

I would start with an allow of ["*"] for your tests, and also for input_headers and make it more restrictive. Also, as a backend, you can use temporarily a KrakenD backend (with an echo endpoint) to discard problems with the backend integration.

From here, honestly, I don't know how I can offer more practical help, as you don't specify your testing process, what headers you are sending, and so on... If it's impossible to reproduce what you are doing, it isn't easy to help.

Your configuration is correct, the tests above are copy and paste of the config you pasted, replacing the 3000 port with 8080.

El dia dijous, 6 de juliol de 2023 a les 9:13:35 UTC+2, jo...@woerd.org va escriure:
To unsubscribe from this group and stop receiving emails from it, send an email to community+unsubscribe@krakend.io.

Jörg Erdmenger

unread,
Jul 7, 2023, 1:38:16 PM7/7/23
to Albert Lombarte, KrakenD Community, Daniel Lopez
Hi Alberto,

thanks for clarifying the auto_options! You gave me some pointers that made some things click. I now have a working version. It was important to me to understand that the OPTIONS call that is provided by the CORS config doesn't actually hit the backend. I then had to fix some other things, i.e. my backend was returning a json array rather than an object and I wasn't aware of the is_collection setting before. So really a big thank you from me.

Jörg

To unsubscribe from this group and stop receiving emails from it, send an email to community+...@krakend.io.
Reply all
Reply to author
Forward
0 new messages