I just finished the tutorials
https://docs.apigee.com/api-platform/tutorials/secure-calls-your-api-through-api-key-validation
I am now trying this API with Try this API in Live Portal. In the API documentation required, if I specify the apikey as a query parameter, somehow I get the right response although I still get {isTrusted: true} with unknown status when I pass the wrong the apikey(shouldn't I get 401 response like the key is wrong or something?)
But, in the API documentation, when I specify the apikey inside header, I get {isTrusted:true} with unknown status whether or not I pass the right API key in Try this API.
The curl command that Try this API generates is correct because I can verify that by running the command in my terminal. But, only in Try this API console, it doesn't work. Am I missing anything? Thank you!
Answer by Sai Saran Vaidyanathan
·
Jul 13, 2020 at 03:31 PM
Hi @hyun jeon
This is due to CORS. Before hitting "Execute" in Try it now, please enable trace in Apigee proxy and also enable Developer tools on your browser. You will see an error due to CORS. You will also see a preflight OPTIONS call that gets called from the browser. This is common with calls made from browser (from another domain). To get this to work, you need to enable CORS. To enable - follow the steps mentioned here
NOTE: If you have added the Verify API Key policy in the Preflow, make sure you add a condition like this
<Step> <Name>verify-api-key</Name> <Condition>request.verb != "OPTIONS"</Condition> </Step>
We don't want this policy executed for the OPTIONS call. Once this is done, try making the call from "Try it now".
Another note: Make sure you are hitting the "https" endpoint of the proxy
@ Sai Saran VaidyanathanThank you sir! CORS was indeed the issue; it failed at the preflight OPTIONS. So, I followed the steps you suggested and am getting the result when I pass the correct api key in the header. But if I could, could I also ask why I am still getting {isTrusted: true} with unknown status when I pass INCORRECT apikeys? Is it a normal behavior of Try this API? But I highly doubt it because in the development console, I am seeing CORS errors when an incorrect API key is passed. What should I do more?
HI @hyun jeon - please include the Add-CORS policy to the FaultRules. All the exceptions are caught using FaultRules
In your proxy endpoint config, add these
<FaultRules/> <DefaultFaultRule name="all"> <AlwaysEnforce>true</AlwaysEnforce> <Step> <Name>Add-CORS</Name> </Step> </DefaultFaultRule>
This means it will add the CORS headers for the exception scenarios too
And when I enable CORS by dragging the CORS Icon into the diagram of preflow of Target Endpoints (like the example in the page that you linked) I get
The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed
Any Idea what it might be?
@Sai Saran Vaidyanathan
Thank you again for your answer; I really appreciate it! But, I am still a little lost. For the initial problem, I was able to fix it by adding your suggestion below
<Step> <Name>verify-api-key</Name> <Condition>request.verb != "OPTIONS"</Condition> </Step><br>
But the problem of receiving {isTrusted:true} persists on incorrect API keys. So I follow your suggestions of enabling CORS by checking "Add CORS headers" when creating the proxy, which results in the preflow diagram being like below (Isn't this what you mean by "enabling CORS" in your answer above? Please correct me if I am wrong)
However, with this CORS policy, I get {isTrusted:true} on both correct and incorrect API keys with the error on the console being "Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed."
Because of that, even when I add the Add-CORS policy to the FaultRules, I still get {isTrusted:true} with the same error on the console.
These are my settings, is there anything wrong? Again, I really appreciate you taking the time for my question!
@hyun jeon - I think your config is wrong. Please remove line 4 - 10 and add them to the Proxy endpoint code. On the left menu, click the default under "Proxyendpoint" and add it before Preflow
@Sai Saran Vaidyanathan
Thank you again sir! By 4 - 10, would you mean
<FaultRules/> <DefaultFaultRule name="all"> <AlwaysEnforce>true</AlwaysEnforce> <Step> <Name>Add-CORS</Name> </Step> </DefaultFaultRule>
If I remove this block from the config of "Add CORS" and add it to the Proxy endpoint code before Preflow, I get
I am not sure but I tried with lowercase like below
<FaultRules/> <DefaultFaultRule name="all"> <AlwaysEnforce>true</AlwaysEnforce> <Step> <Name>add-cors</Name> </Step> </DefaultFaultRule> <br>
Though I was able to deploy, the problem persists..
Thank you!
Thank you sir! I have ended up fixing the problem by putting together all the suggestions you have kindly provided! It turns out that I needed these 2 blocks of code in my default
<Step> <Name>verify-api-key</Name> <Condition>request.verb != "OPTIONS"</Condition> </Step> && <FaultRules/> <DefaultFaultRule name="all"> <AlwaysEnforce>true</AlwaysEnforce> <Step> <Name>Add-CORS</Name> </Step> </DefaultFaultRule><br>
Which makes me wonder why I get CORS errors when I add these 2 blocks to my default
<Flows> <Flow name="OptionsPreFlight"> <Request/> <Response> <Step> <Name>AM-AddCORS</Name> </Step> </Response> <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition> </Flow> </Flows> && <RouteRule name="NoRoute"> <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition> </RouteRule> <br>
What are these? According to the documentation you linked earlier, they are supposed to help handle preflight requests. But With them being in default, I rather get CORS errors. Could I ask maybe why?
Thank you again for your help and kind suggestions!
Glad you got it working. I will try and explain each below
<Step> <Name>verify-api-key</Name> <Condition>request.verb != "OPTIONS"</Condition> </Step>
The above it to execute the policy and if the condition evaluates to true, it executes the policy
<FaultRules/> <DefaultFaultRule name="all"> <AlwaysEnforce>true</AlwaysEnforce> <Step> <Name>Add-CORS</Name> </Step> </DefaultFaultRule><br>
Any exception thrown by a policy in Apigee raises a fault (you can think it like an exception). To catch those you need to use the FaultRules to execute like catch block. Check this link for more info. DefaultFaultRule are the ones that executes after the FaultRules are executed.
<Flow name="OptionsPreFlight"> <Request/> <Response> <Step> <Name>AM-AddCORS</Name> </Step> </Response> <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition> </Flow><br>
is a Conditional flow that executes on a Condition. In the above block, it gets called with the Preflight OPTIONS call occur. And when that occurs, it sets the CORS headers in the response
<RouteRule name="NoRoute"> <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition> </RouteRule><br>
RouteRule is used to determine the target endpoint where the request needs to be sent to. For the OPTIONS call, we dont need to send to a backend target. So we set it with no target endpoints. Compare this routerule with the default RouteRule you have in your proxy. For more info on Route Rules, check this link
In your case, when you passed an invalid API KEY, Apigee raised a fault and it went to the FaultRule,DefaultFaultRule section. And in that section, since the response did not include the CORS headers, the portal was not able to render the response. Hence we had to include the CORS Assign Message policy to the FaultRule as well.
hope the blocks and the explanation clarifies
Wow, thank you so much for your thorough & concise explanation at such a moment when I was reading the documentations.
One last thing that bothers me though is the two blocks (Flow "OptionPreFlight" and RouteRule "NoRoute"). When I add either one or both to my default, I get CORS errors.
According to the documentation you pointed to earlier, they are supposed to help handle preflight requests. But it rather causes CORS errors. Would you please your share opinion as to maybe why? Because without them, it works perfectly fine on both valid and invalid api keys.