Search code examples
javascriptcorsxmlhttprequestcross-origin-read-blockingkrakend

Cross-Origin Read Blocking (CORB) problem with KrakenD - "application/json" response from POST rejected by Chrome


auth.js:84 Cross-Origin Read Blocking (CORB) blocked cross-origin response http://myserver/auth with MIME type application/json.

This doesn't work with Firefox either, although the Firefox error message is more generic. Oddly enough, Firefox's Network panel shows that the response I wanted actually gets delivered, the browser just doesn't accept the response to pass it on to my JavaScript code.

This is the CORS setup from my krakend.json file:

        "github_com/devopsfaith/krakend-cors": {
            "allow_origins": ["http://localhost:61552"],
            "allow_headers": ["Origin", "Authorization", "Content-Type", "Accept", "X-Auth-Token", "Referer", "User-Agent"],
            "expose_headers": ["Content-Type", "Content-Length"],
            "allow_credentials": true,
            "allow_methods": ["GET", "HEAD", "POST", "OPTIONS"]
        }

And this is the particular endpoint being called:

    "endpoints": [{
            "endpoint": "/auth",
            "method": "POST",
            "output_encoding": "no-op",
            "extra_config": {
                "github.com/devopsfaith/krakend-ratelimit/juju/router": {
                    "maxRate": 20,
                    "clientMaxRate": 8,
                    "strategy": "ip"
                }
            },
            "backend": [{
                "url_pattern": "/connect/token",
                "encoding": "no-op",
                "sd": "dns",
                "host": ["identity-server.service.consul"],
                "disable_host_sanitize": true
            }]
        },

My JavaScript request looks like this:

    xhr.open('POST', url);
    xhr.setRequestHeader('Accept', 'application/json');
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.withCredentials = true;
    xhr.onreadystatechange = function () {
       ...
    }

    xhr.send(...

I thought of trying to change the content type of the response to text/plain in case that would help, but I don't currently have access to the code that generates that response, and I don't know if that would help anyway.

When I make this same request from either a node.js server or an app like Postman, everything comes back correctly, and the headers I'd want to see that I think should be enough to make CORS happy are present (access-control-allow-credentials: true, access-control-allow-origin: *)


Solution

  • I finally found any answer for this.

    The first problem was that, when using xhr.withCredentials = true, it isn't good enough to get a response header of access-control-allow-origin: *. The response header must contain the original origin of the request itself, such as access-control-allow-origin: https://example.com.

    The second problem was the way the CORS module used by kraken deals with wildcard domains. If you use "allow_origins": [] or "allow_origins": ["*"], the server responds with access-control-allow-origin: * no matter what.

    I didn't want to have to whitelist every host that might want to use this server, however.

    Fortunately, someone was able to point me at the source code used by kraken to handle CORS (at https://github.com/rs/cors), and it turns out that if you use any other kind of wildcard expression other than "*" for everything, like "http*", then the server echoes back the original host, and all is well! My config is now:

    "allow_origins": ["http*"]

    NOTE: Doing this could be dangerous! If you're putting sensitive data into cookies, that same data can become available to any other websites this way.