Unable to get CORS to work in Google Chrome

Not applicable

Hi, I am trying to get CORS to work in Google Chrome, but till now unsuccesfully.

I have the following policies:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Spike-Arrest</Name>
            </Step>
            <Step>
                <Name>Verify-API-Key-1</Name>
            </Step>
            <Step>
                <Name>remove-query-param-apikey</Name>
            </Step>
            <Step>
                <Name>Quota</Name>
            </Step>
        </Request>
        <Response>
            <Step>
                <Name>add-cors</Name>
            </Step>
        </Response>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Response>
            <Condition>request.verb == "OPTIONS"</Condition>
        </Flow>
        <Flow name="All">
            <Description>...</Description>
            <Request/>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/") and (request.verb = "GET")</Condition>
        </Flow>    
    </Flows>
    <HTTPProxyConnection>
        <BasePath>...</BasePath>
        <Properties/>
        <VirtualHost>...</VirtualHost>
        <VirtualHost>...</VirtualHost>
        <VirtualHost>...</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS"</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>...</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

and

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TargetEndpoint name="Batch">
    <Description/>
    <FaultRules/>
    <Flows/>
    <HTTPTargetConnection>
        <LoadBalancer>
            <Server name="..."/>
        </LoadBalancer>
        <Path>...</Path>
        <SSLInfo>
            <Enabled>...</Enabled>
            <ClientAuthEnabled>...</ClientAuthEnabled>
            <KeyStore>...</KeyStore>
            <KeyAlias>...</KeyAlias>
            <TrustStore>...</TrustStore>
        </SSLInfo>
    </HTTPTargetConnection>
    <PreFlow name="PreFlow">
        <Request/>
        <Response>
            <Step>
                <Name>add-cors</Name>
            </Step>
        </Response>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</TargetEndpoint>

and the following Javascript:

jQuery.ajax({
		url : '...',
		type : 'GET',
		beforeSend: function (request)
        {
			request.setRequestHeader("apikey", key),
		success : function(result){
			console.log(result);
		},
		error : function(result){
			console.log(result);
		}
	});

And the following add-cors policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Add>
        <Headers>
            <Header name="Access-Control-Allow-Origin">*</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, apikey, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
        </Headers>
    </Add>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

And this is the answer I get in the console:

OPTIONS https://.. 401 (Unauthorized)

XMLHttpRequest cannot load ... . Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '...' is therefore not allowed access. The response had HTTP status code 401.

Any help is appreciated!

0 11 6,452
11 REPLIES 11

@jan.willem.hennink, you have added CORS in the normal flow (Success) but not in the fault process (Fail). Flow gets terminated and goes into fault processing when ever there is a fault. Define fault/default fault rule and then add the CORS policy to add the headers to the error response. One more thing.You have added CORS in all the flows which is not required. Just add it under the response of the Post flow and also use <Set> instead of <Add> to avoid duplication of Allow-Origins.

Hi Mahammed, thank you for your answer! Can you help us out a bit and indicate where changes are needed and how it should look like? It would help us a great deal. Thank you in advance!

@jan.willem.hennink, PFB updated xml for ProxyEndpoint. Add the DefaultFaultRule in the TargetEndpoint also for handling back end errors.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <DefaultFaultRule name="Default">
    	<Step>
            <Name>add-cors</Name>
        </Step>
        <AlwaysEnforce>true</AlwaysEnforce>
    </DefaultFaultRule>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Spike-Arrest</Name>
            </Step>
            <Step>
                <Name>Verify-API-Key-1</Name>
            </Step>
            <Step>
                <Name>remove-query-param-apikey</Name>
            </Step>
            <Step>
                <Name>Quota</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response>
	    <Step>
                <Name>add-cors</Name>
            </Step>
	<Response>
    </PostFlow>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response/>
            <Condition>request.verb == "OPTIONS"</Condition>
        </Flow>
        <Flow name="All">
            <Description>...</Description>
            <Request/>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/") and (request.verb = "GET")</Condition>
        </Flow>    
    </Flows>
    <HTTPProxyConnection>
        <BasePath>...</BasePath>
        <Properties/>
        <VirtualHost>...</VirtualHost>
        <VirtualHost>...</VirtualHost>
        <VirtualHost>...</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS"</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>...</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

And the following add-cors policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Set>
        <Headers>
            <Header name="Access-Control-Allow-Origin">*</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, apikey, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE, OPTIONS</Header>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

Hi Mahammed, thank you, but I now get the following error message in Chrome console:

jquery-3.1.1.js:9536 OPTIONS https://.. 401 (Unauthorized)
send @ jquery-3.1.1.js:9536
ajax @ jquery-3.1.1.js:9143
(anonymous) @ (index):29
(index):1 XMLHttpRequest cannot load .... Response for preflight has invalid HTTP status code 401
(index):45 Object {readyState: 0, status: 0, statusText: "error"}

By the way, I am using an apiKey in the header of my request to authenticate.. does that provide this issue related to my client side javascript?

Hi @Mahammad Feroz can you help me out? Do you see anything missing in my config? I still cant get it to work..

Thanks in advance!

Hi @Mahammad Feroz I do see that when passing the API Key as a query param, chrome works perfectly fine. But passing it as a header param, chome keeps telling me I have a 401 unauthorized. I think somewhere (in chrome of edge) the header api key gets trimmed.

Not applicable

I get two different results in Internet Explorer and Chrome, where Internet Explorer is working and Chrome is not.

Looking at the Trace, Chrome results in an OPTIONS call, IE in a GET call:

Internet Explorer:

Request Received from Client
GET ....
200 OK
Request Headers
Accept 	*/*
Accept-Encoding 	gzip,deflate,peerdist
Accept-Language 	nl-NL
apikey 	....
Host 	....
User-Agent 	Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; managedpc; rv:11.0) like Gecko
X-Forwarded-For 	....
X-Forwarded-Port 	80
X-Forwarded-Proto 	http
X-P2P-PeerDist 	Version=1.1
X-P2P-PeerDistEx 	MinContentInformation=1.0,MaxContentInformation=2.0


Google Chrome:

Request Received from Client
OPTIONS ....
401 Unauthorized
Request Headers
Accept 	*/*
Accept-Encoding 	gzip,deflate,sdch
Accept-Language 	en-US,en;q=0.8
Access-Control-Request-Headers 	apikey
Access-Control-Request-Method 	GET
Host 	....
Origin 	null
User-Agent 	Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/55.0.2883.87 Safari/537.36
X-Forwarded-For 	.....
X-Forwarded-Port 	80
X-Forwarded-Proto 	http

@jan.willem.hennink, could you attach the proxy here for review and update?

Thank you @Mahammad Feroz

hereby the config:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <FaultRules/>
    <DefaultFaultRule name="Default">
        <Step>
            <Name>add-cors</Name>
        </Step>
        <AlwaysEnforce>true</AlwaysEnforce>
    </DefaultFaultRule>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Spike-Arrest</Name>
            </Step>
            <Step>
                <Name>Verify-API-Key-1</Name>
            </Step>
            <Step>
                <Name>remove-query-param-apikey</Name>
            </Step>
            <Step>
                <Name>Quota</Name>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <PostFlow name="PostFlow">
        <Request/>
        <Response>
            <Step>
                <Name>add-cors</Name>
            </Step>
        </Response>
    </PostFlow>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response/>
            <Condition>request.verb == "OPTIONS"</Condition>
        </Flow>
        <Flow name="All">
            <Description>All airports which are available</Description>
            <Request/>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/") and (request.verb = "GET")</Condition>
        </Flow>
        <Flow name="By location">
            <Description>By location</Description>
            <Request/>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "/locationcode/{locationcode}") and (request.verb = "GET")</Condition>
        </Flow>
    </Flows>
    <HTTPProxyConnection>
        <BasePath>...</BasePath>
        <Properties/>
        <VirtualHost>secure</VirtualHost>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>https_vhost</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS"</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>...</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

and add-cors:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Set>
        <Headers>
            <Header name="Access-Control-Allow-Origin">*</Header>
            <Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, apikey, authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE, OPTIONS</Header>
        </Headers>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>

@jan.willem.hennink, Could you download the proxy and attach it here?

Hi @Mahammad Feroz I fixed it by skipping header key valiation for option requests. It works perfectly now, since the option call results in a get call which checks the key. Thank you!

btw: I nog use this step:

<Step>
   <Name>verify-api-key</Name>
   <Condition>request.verb != "OPTIONS"</Condition>
</Step>