How to deal with CORS when API key is in header?

When dealing with cross-site requests, a browser will do a pre-flight check for CORS headers. I've set up the right policies in my proxy to handle those. However, when a GET request tries to use an apikey in the header, the browser's pre-flight check fails because it doesn't know to send the apikey with the OPTIONS request, so the proxy returns a 401 Unauthorized because it doesn't see the key.

This auth rejection means my CORS headers never get set on OPTIONS requests, the browser's pre-flight check never passes, and therefore the browser won't make the subsequent XHR GET request.

Sure, I could pass the apikey in the query string, but that isn't a great practice. What's the right answer?

0 3 4,061
3 REPLIES 3

Not applicable

OPTIONS requests shouldn't be validated against the key, as there's no exchange of sensitive data. Instead, their origin header should be validated against a valid set of domain names supported by the API, which the browser sets in the origin header.

What this means in Edge for OPTIONS requests, is that you should skip API Key Verification Policy and enable verification of origin header. Verification of the header can be implemented with a JavaScript policy along with regular expression

For Nodejs API Proxies, you can leverage cors npm module and implement similar logic for origin header validation.

adas
Participant V

Agree with @Diego Zuluaga. There should be a conditional flow for OPTIONS verb that doesn't have the apikey validation. It should simple respond with the CORS headers. If you want to validate origin headers etc. do that in a custom policy like javascript or raisefault and respond appropriately.

jovaniac
Participant II
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