Development Portal Try this API - Receiving {"isTrusted": true}

hj2509
Participant I

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!

Solved Solved
0 17 941
1 ACCEPTED SOLUTION

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

View solution in original post

17 REPLIES 17

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?

Dont think you need this.

@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)

10118-preflow.jpg

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!

10119-1.jpg

10121-3.jpg

10120-2.jpg

@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

10122-4.jpg

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!

I cant see the screenshot you attached

Your default should be something like this

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <DefaultFaultRule name="all">
        <AlwaysEnforce>true</AlwaysEnforce>
        <Step>
            <Name>AM-AddCORS</Name>
        </Step>
    </DefaultFaultRule>
    <PreFlow name="PreFlow">
        <Request>
            <Step>
                <Name>Verify-API-Key</Name>
                <Condition>request.verb != "OPTIONS"</Condition>
            </Step>
        </Request>
        <Response/>
    </PreFlow>
    <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>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <HTTPProxyConnection>
        <BasePath>/test-flows</BasePath>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

@Sai Saran Vaidyanathan

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

@Sai Saran Vaidyanathan

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.

Not sure I understand your question completely... You need to add both block to enable CORS and also take care of the Pre-flight transactions. Apigee is like a reverse proxy to your target but in this case for the OPTIONS call, there is no backend, so you configure the RouteRule in Apigee to tell there is no backend. So Apigee generates the response and sends it back to the client. Having no backend is a common pattern. For example if you were using Apigee as the OAuth server (token store), the OAuth API will have no backend, so there will be a No Route rule configured. Hope that clarifies

@Sai Saran Vaidyanathan

Thank you! Everything makes perfect sense.

One last quick question if I you don't mind. If I am NOT using Apigee as the OAuth server(token server), is the "NoRoute" rule completely optional?

Because, my proxy seems to be working okay without the rule. In this case, I assume, the NoRoute rule may be used for better performance? since it does not forward preflight requests to backend? Is my understanding correct?

If you have a backend then you need to have a RouteRule that sends the request to the backend. However for the preflight OPTIONS call, you will have a noRoute with the Condition

<RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>

Its not about performance. Its about functionality. For Pre-flight, you need to be within Apigee as thats what the client is interacting with. Your backend will be on another domain. Your client is interacting with the APIs exposed in Apigee. For Preflight - you need to have noRoute

Not applicable

It's an interesting method.