CORS policy in my API proxy when using OAuth 2.0

Hi guys I have a similar problem which @Zhongli Wu faced few days ago....

His thread - http://community.apigee.com/questions/2890/add-usable-cors-policy-in-my-api-proxy-when-using.html?so...

I tried @Maruti Chand and @mukundha@apigee.com solutions from that thread but they didn't work for me...

Here are my details...

CORS Policy...

<AssignMessage async="false" continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <FaultRules/>
    <Properties/>
    <Add>
        <Headers>
            <Header name="Access-Control-Allow-Origin">{request.header.origin}</Header>
            <Header name="Access-Control-Allow-Headers">{reqHeaders}</Header>
            <Header name="Access-Control-Max-Age">3628800</Header>
            <Header name="Access-Control-Allow-Methods">GET</Header>
        </Headers>
    </Add>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
    <AssignTo createNew="false" transport="http" type="response"/>
  
</AssignMessage>

Ajax Call..

function displayMotorQuote(){
	
  var motorQuoteDetailsUrl = "https://siddharth1-test.apigee.net/i_vechile_quote-2";	
  
  $.ajax({
     url: motorQuoteDetailsUrl,
     type: 'GET',
 
 beforeSend: function(xhr) {
 // xhr.setRequestHeader("Access-Control-Allow-Origin", "*");
    xhr.withCredentials = true;
    xhr.setRequestHeader('Authorization', 'bearer 6Y1zOQfYMQztBGLo3oMVrB5Dvmm4');
  },

Error Details..

XMLHttpRequest cannot load https://siddharth1-test.apigee.net/i_vechile_quote-2. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 401.

I have attached my proxy...have a look at it..

i-vechile-quote-2-rev5-2015-04-20.zip

Solved Solved
2 10 5,643
1 ACCEPTED SOLUTION

Not applicable

Barahalikar Siddharth and @Zhongli Wu,

Looks like both of you have the same issues . I updated the proxy that was attached by @Barahalikar Siddharth here .

Made some modifications and pls use it as it is for your testing , Pls import on to your org, change the virtualhost and test with the browser to see if it is working as expected . In the network calls you should see below request and response headers .

Pls try it out and let me know if you see any issues . Once you have a working proxy , then you can modify as per your requirements.

OPTIONS /i_vechile_quote-2 HTTP/1.1
> Authorization: Basic YWRta
> User-Agent: curl/7.41.0
> Host: test.com
> Accept: */*
> Access-Control-Request-Method:GET
> Access-Control-Request-Headers:Accept, Authorization
> Origin:http://api.bob.com



< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: Accept, Authorization
< Access-Control-Max-Age: 3628800
< Access-Control-Allow-Methods: GET
< Content-Length: 0
< Set-Cookie: ap_44_SV=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/
< Cache-control: private
> GET /i_vechile_quote-2 HTTP/1.1
> Authorization: Basic YWRta
> User-Agent: curl/7.41.0
> Host: test.com
> Accept: */*
> Origin:http://api.bob.com



//posting just headers here from the response


< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Wed, 22 Apr 2015 05:50:44 GMT
< Server: Apache-Coyote/1.1
< Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 21-Apr-2015 05:50:44 GMT
< x-apigee-serverprocessingtime: 82
< Content-Length: 4573
< Set-Cookie: ap_44_SV=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/
< Cache-control: private

View solution in original post

10 REPLIES 10

@Barahalikar Siddharth

To my understanding, the OPTIONS pre flight request cannot perform Authorization. Please see here: http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0

So your issue is that the OAuth policy is checking the Authorization header for the OPTIONS request, but it is missing the Authorization header. So, you could change your API to skip the OAuth policy for OPTIONS requests.

<Step>
     <FaultRules/>
     <Name>OAuth-v20-1</Name>
     <Condition>request.verb != "OPTIONS"</Condition>
</Step>

Also make sure that you then add the Authorization header to your allowed headers in the "Add CORS" policy (since it is obviously not in the reqHeaders variable)

<Header name="Access-Control-Allow-Headers">{reqHeaders}, Authorization</Header>

Thanks @kbouwmeester & @Maruti Chand

//#Avoid redundant headers . For example : your target curl -vhttps://api.usergrid.com/siddharth1/sandbox//i_vechile_quote is already returning Access-Control-Allow-Origin: * and you are returning again so the value will be *, {request.header.origin}
#You just need Access-Control-Allow-Origin: * header in actual response but not all access-control headers.//

Sorry, I did not understand this, can you explain me how to avoid redundant header?

Trace screenshot,

341-oauth-trace.jpg

#Your target is sending Access-Control-Allow-Origin: * and you are adding one more same header so the values go to the browser as *,your value which will be rejected by the browser .

#In the actual request GET you don't need to respond with all Access-Control-Allow headers and you just need Access-Control-Allow-Origin header .

Hi, @Barahalikar Siddharth, did you finally solve it? I just can't find where the problem is. Thanks!

@Zhongli Wu

Yeah it is working for me. Actually my problem was,

my target was sending Access-Control-Allow-Origin: * and I was adding one more same header, so the values go to the browser as *,*(my value) which were rejected by the browser. 

So Maruti Chand, modified my proxy added an JS policy to remove the extra header.

If you still didn't get the solution. Please attach your proxy I'll have a look.

Hi Barahalikar, Thanks! weatherxml-rev2-2015-05-05.zip

I've uploaded my proxy in this reply. It still does not exist after modification. Could you please look at it and help me if possible? I really appreciate you kind help!

Not applicable

@Barahalikar Siddharth

Few points

#As kbouwmeester mentioned , OPTIONS is sent by the browser and it will not send token .

#Read the headers in your request flow(proxy) and not target flow as a best practice as sometimes it might get modified.

#Avoid redundant headers . For example : your target curl -v https://api.usergrid.com/siddharth1/sandbox//i_vechile_quote is already returning Access-Control-Allow-Origin: * and you are returning again so the value will be *, {request.header.origin}

#You just need Access-Control-Allow-Origin: * header in actual response but not all access-control headers.

Not applicable

Barahalikar Siddharth and @Zhongli Wu,

Looks like both of you have the same issues . I updated the proxy that was attached by @Barahalikar Siddharth here .

Made some modifications and pls use it as it is for your testing , Pls import on to your org, change the virtualhost and test with the browser to see if it is working as expected . In the network calls you should see below request and response headers .

Pls try it out and let me know if you see any issues . Once you have a working proxy , then you can modify as per your requirements.

OPTIONS /i_vechile_quote-2 HTTP/1.1
> Authorization: Basic YWRta
> User-Agent: curl/7.41.0
> Host: test.com
> Accept: */*
> Access-Control-Request-Method:GET
> Access-Control-Request-Headers:Accept, Authorization
> Origin:http://api.bob.com



< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Headers: Accept, Authorization
< Access-Control-Max-Age: 3628800
< Access-Control-Allow-Methods: GET
< Content-Length: 0
< Set-Cookie: ap_44_SV=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/
< Cache-control: private
> GET /i_vechile_quote-2 HTTP/1.1
> Authorization: Basic YWRta
> User-Agent: curl/7.41.0
> Host: test.com
> Accept: */*
> Origin:http://api.bob.com



//posting just headers here from the response


< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Content-Type: application/json
< Date: Wed, 22 Apr 2015 05:50:44 GMT
< Server: Apache-Coyote/1.1
< Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Tue, 21-Apr-2015 05:50:44 GMT
< x-apigee-serverprocessingtime: 82
< Content-Length: 4573
< Set-Cookie: ap_44_SV=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/
< Cache-control: private

@Maruti Chand Thank you...it is working perfectly.

hey guys, I implemented something like that and it served me correctly.
In the proxy enpoint we must place in the preflow the next call of a Flowcallout to invoke a sharedflow which will have the policy of CORS

<PreFlow name="PreFlow">
<Request>
<Step>
<Name>FC-CORS</Name>
</Step>
<Step>
<Name>FC-OAuth2</Name>
</Step>
</Request>
<Response/>
</PreFlow>

Definition of flowcallout, where we invoke the sharedflow

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<FlowCallout async="false" continueOnError="false" enabled="true" name="FC-CORS">
<DisplayName>FC-CORS</DisplayName>
<FaultRules/>
<Properties/>
<SharedFlowBundle>OPTIONS-CORS-Headers-Response</SharedFlowBundle>
</FlowCallout>

definition of sharedflow

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SharedFlow name="default">
<Step>
<Name>OPTIONS-CORS-Headers-Response</Name>
<Condition>request.verb == "OPTIONS"</Condition>
</Step>
</SharedFlow>

definition of the policy of raisefull, where we will indicate the headers of Access-Control-Allow-Origin with * that will allow the invocation from our browser

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RaiseFault async="false" continueOnError="false" enabled="true" name="OPTIONS-CORS-Headers-Response">
<DisplayName>OPTIONS CORS Headers Response</DisplayName>
<Properties/>
<FaultResponse>
<Set>
<Headers>
<Header name="Access-Control-Allow-Origin">*</Header>
<Header name="Access-Control-Allow-Headers">origin, x-requested-with, accept, ucsb-api-key, ucsb-api-version, authorization</Header>
<Header name="Access-Control-Max-Age">3628800</Header>
<Header name="Access-Control-Allow-Methods">GET, PUT, POST, DELETE</Header>
</Headers>
<Payload contentType="text/plain"/>
<StatusCode>200</StatusCode>
<ReasonPhrase>OK</ReasonPhrase>
</Set>
</FaultResponse>
<IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</RaiseFault>

angular:

const httpOptions2= { headers:newHttpHeaders({ 'Authorization':'Bearer token' }) };

obtenerCatalogos():Observable<any> { return this.httpClient.get<any>(uriApigee+'endpointapigee',httpOptions2); }

Regars