Enabling CORS worked but only when I don't add an Authorization header to original request

I am making a simple reverse proxy pass-through with cors enabled that I call from a non deployed html file with scripting to call the API. Origin is therefore null.

I am able to get the response back to the browser only when I don't include the Authorization header and hardcode it in a policy. What can I do to include the header in the html file?

My CORS policy looks like this:

	<?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, Authorization</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">OPTIONS, GET, PUT, POST, DELETE</Header>
        </Headers>
    </Add>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
</AssignMessage>
0 4 231
4 REPLIES 4

CORS is sort of tricky.

The CORS-compliant client (all mainstream, off the shelf browsers) can. get CORS information in one of two ways:

  • via an explicit CORS pre-flight request. It uses the OPTIONS verb.
  • via an implicit set of response headers on a prior request.

It's possible that your HTML client has some information about allowed headers, via one of these mechanisms, and is observing that restriction. In other words it's possible that the policy you've shown is NOT the thing that is delivering the CORS information that the browser is actively using.

Double check that there is no OPTIONS call that you are inadvertently not handling, and double check that all other responses (eg for GET requests) also have the appropriate CORS headers set.

One option for possibly avoiding all this CORS stuff is to serve the static HTML page from the Apigee endpoint itself. Then the origin is the same and CORS is irrelevant.

Thank you.

Here is my code (sorry for not including before)

 getTags() {
  this.setState({ topic: 'Tags Are Loading...'});
    var xhr = new XMLHttpRequest()
    xhr.addEventListener('load', () => {
      this.setState({ tags: JSON.parse(xhr.response).data});
      this.setState({ topic: 'Tags Are Loaded -->'});
      this.setState({ selecttags: 'Select One or More Tags'});
      this.setState({downloadcsv: ''});
      return JSON.parse(xhr.response);
})
    xhr.open('GET', 'https://xxxxxxx-16xxxxx-eval-test.apigee.net/newbase/tags')
    xhr.setRequestHeader("Authorization", "Bearer "+this.token);
    xhr.send()
  }

Nothing else in the html file is relevant to this call. When I include the header, it does not work (CORS preflight error above) and when I don't include it (but hardcode in the proxy), it works.


Are you suggesting I need to add some more headers here in addition to the Authorization? Like Access-Control-Allow-Headers, etc even though I didn't need them before?

Thank you.

Are you suggesting I need to add some more headers here in addition to the Authorization? Like Access-Control-Allow-Headers, etc even though I didn't need them before?

No. Clients don't send such headers. Headers with names like Access-Control-Allow-* are CORS response headers. They are sent by the server.

When I include the header, it does not work (CORS preflight error above) and when I don't include it (but hardcode in the proxy), it works.

That is new information. I don't think I saw anything in your original question that mentioned a preflight. Is there a preflight request, and if so, Is the API Proxy handling the preflight? I suspect not.

Please Re-read my original answer. There are two ways a user-agent gets CORS information: with a preflight or with a set of headers from a prior request. For one of those two cases, YOUR api proxy is not sending the correct Access-Control-Allow-Headers header.

I see your AssignMessage policy. I'm not saying the policy is wrong. I am saying that the assignmessage policy is not being executed for, either the preflight, or for a different request that we haven't discussed.

Probably it's the preflight. Make sure you are clear on what a preflight request is, and make sure your API Proxy is handling it, and make sure the response includes the appropriate CORS headers.

Also, if I make an Assign Message Policy like this and put it in the preflow target endpoint request:

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<AssignMessage async="false" continueOnError="false" enabled="true" name="Assign-Message-1">
    <DisplayName>Assign Message-1</DisplayName>
    <Properties/>
    <Copy source="request">
        <Headers/>
        <QueryParams/>
        <FormParams/>
        <Payload/>
        <Verb/>
        <StatusCode/>
        <ReasonPhrase/>
        <Path/>
    </Copy>
    <Remove>
        <Payload/>
    </Remove>
    <Add>
        <Headers>
            <Header name="Authorization">{authcors}</Header>
        </Headers>
        <QueryParams/>
        <FormParams/>
    </Add>
    <Set>
        <QueryParams/>
        <FormParams/>
        <!-- <Verb>GET</Verb> -->
        <Path/>
    </Set>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="request"/>
</AssignMessage>

It does not work unless I replace with a hardcoded value. I still get:

from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

The only thing I'm stuck on is how do I use the actual header I'm sending in from here:

getTags() {
  this.setState({ topic: 'Tags Are Loading...'});
    var xhr = new XMLHttpRequest()
    xhr.addEventListener('load', () => {
      this.setState({ tags: JSON.parse(xhr.response).data});
      this.setState({ topic: 'Tags Are Loaded -->'});
      this.setState({ selecttags: 'Select One or More Tags'});
      this.setState({downloadcsv: ''});
      return JSON.parse(xhr.response);
})
    xhr.open('GET', 'https://xxxxxxxx-16xxxxxxxd-eval-test.apigee.net/newbase/tags')
    xhr.setRequestHeader("Authorization", "Bearer "+this.token);
    xhr.send()
  }