CORS policy

This page applies to Apigee and Apigee hybrid.

View Apigee Edge documentation.

policy icon

What

Cross-origin resource sharing (CORS) is a standard mechanism that allows JavaScript XMLHttpRequest (XHR) calls executed in a web page to interact with resources from non-origin domains. CORS is a commonly implemented solution to the same-origin policy that is enforced by all browsers.

For example, if you make an XHR call to the Twitter API from JavaScript code executing in your browser, the call will fail. This is because the domain serving the page to your browser is not the same as the domain serving the Twitter API. CORS provides a solution to this problem by allowing servers to opt-in if they wish to provide cross-origin resource sharing.

This CORS policy allows Apigee customers to set CORS policies for APIs consumed by web applications.

This policy is a Standard policy and can be deployed to any environment type. For information on policy types and availability with each environment type, see Policy types.

<CORS> element

Defines the CORS policy.

Default Value See Default Policy tab, below
Required? Required
Type Complex object
Parent Element N/A
Child Elements <AllowCredentials>
<AllowHeaders>
<AllowMethods>
<AllowOrigins>
<DisplayName>
<ExposeHeaders>
<GeneratePreflightResponse>
<IgnoreUnresolvedVariables>
<MaxAge>

The <CORS> element uses the following syntax:

Syntax

The <CORS> element uses the following syntax:


<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <DisplayName>DISPLAY_NAME</DisplayName>
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <AllowMethods>[GET, PUT, POST, DELETE, ...|*]</AllowMethods>
  <AllowHeaders>[origin, x-requested-with, accept, content-type, ...]</AllowHeaders>
  <ExposeHeaders>[X-CUSTOM-HEADER-A, X-CUSTOM-HEADER-B, ... | *]</ExposeHeaders>
  <MaxAge>[integer|-1]</MaxAge>
  <AllowCredentials>[false|true]</AllowCredentials>
  <GeneratePreflightResponse>[false|true]</GeneratePreflightResponse>
  <IgnoreUnresolvedVariables>[false|true]</IgnoreUnresolvedVariables>
</CORS>

Default policy

The following example shows the default settings when you add the CORS policy to your flow in the Edge UI:

<CORS continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <AllowOrigins>{request.header.origin}</AllowOrigins>
    <AllowMethods>GET, PUT, POST, DELETE</AllowMethods>
    <AllowHeaders>origin, x-requested-with, accept, content-type</AllowHeaders>
    <ExposeHeaders>*</ExposeHeaders>
    <MaxAge>3628800</MaxAge>
    <AllowCredentials>false</AllowCredentials>
    <GeneratePreflightResponse>true</GeneratePreflightResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

When you insert a new CORS policy in the Apigee UI, the template contains stubs for all possible operations. Typically, you select which operations you want to perform with this policy and remove the rest of the child elements. For example, if you want to specify the HTTP methods allowed to access the resource, use the <AllowMethods> element and remove the other child elements from the policy to make it more readable.

This element has the following attributes that are common to all policies:

Attribute Default Required? Description
name N/A Required

The internal name of the policy. The value of the name attribute can contain letters, numbers, spaces, hyphens, underscores, and periods. This value cannot exceed 255 characters.

Optionally, use the <DisplayName> element to label the policy in the management UI proxy editor with a different, natural-language name.

continueOnError false Optional Set to false to return an error when a policy fails. This is expected behavior for most policies. Set to true to have flow execution continue even after a policy fails. See also:
enabled true Optional Set to true to enforce the policy. Set to false to turn off the policy. The policy will not be enforced even if it remains attached to a flow.
async   false Deprecated This attribute is deprecated.

Each of the child elements is described in the sections that follow.

Examples

Examples are provided for all of the child elements in the following sections.

Child element reference

This section describes the child elements of <CORS>.

<AllowCredentials>

Indicates whether the caller is allowed to send the actual request (not the preflight) using credentials. Translates to the Access-Control-Allow-Credentials header.

Default Value If not specified, Access-Control-Allow-Credentials will not be set.
Required? Optional
Type Boolean
Parent Element <CORS>
Child Elements None

The <AllowCredentials> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <AllowCredentials>[false|true]</AllowCredentials>
</CORS>
      

Example

This example sets the Access-Control-Allow-Credentials header to false. That is, the caller is not allowed to send the actual request (not the preflight) using credentials.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <AllowCredentials>false</AllowCredentials>
</CORS>

<AllowHeaders>

List of HTTP headers that can be used when requesting the resource. Serialized to the Access-Control-Allow-Headers header.

Default Value Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers
Required? Optional
Type String, with message template* support
Parent Element <CORS>
Child Elements None

* For more information, see What is a message template?

The <AllowHeaders> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <AllowHeaders>[origin, x-requested-with, accept, content-type, ...]</AllowHeaders>
</CORS>

Example

CORS AllowOrigins example

This example specifies the HTTP headers that can be used when requesting the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <AllowHeaders>origin, x-requested-with, accept, content-type</AllowHeaders>
</CORS>

<AllowMethods>

List of HTTP methods allowed to access the resource. The content will be serialized into the Access-Control-Allow-Methods header.

Default Value GET, POST, HEAD, OPTIONS
Required? Optional
Type String, with message template* support
Parent Element <CORS>
Child Elements None

* For more information, see What is a message template?

The <AllowMethods> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <AllowMethods>[GET, PUT, POST, DELETE, ...|*]</AllowMethods>
</CORS>

Example:
List

This example specifies the HTTP methods that are allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <AllowMethods>GET, PUT, POST, DELETE</AllowMethods>
</CORS>

Example:
Wildcard

This example specifies that all HTTP methods are allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <AllowMethods>*</AllowMethods>
</CORS>

<AllowOrigins>

A list of origins that are allowed to access the resource. Use an asterisk (*) to enable access to a resource from any origin. Otherwise, provide an allow list of comma-separated origins. If a match is found, then the outgoing Access-Control-Allow-Origin is set to the origin as provided by the client.

Default Value N/A
Required? Required
Type String, with message template* support
Parent Element <CORS>
Child Elements None

* For more information, see What is a message template?

The <AllowOrigins> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
</CORS>

Example:
Single URL

This example specifies a single URL origin that is allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>https://www.w3.org</AllowOrigins>
</CORS>

Example:
Multiple URLs

This example specifies multiple origins that are allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>https://www.w3.org, https://www.apache.org</AllowOrigins>
</CORS>

Example:
Context variable

This example specifies a context variable that represents one or more origins that are allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{origins.list}</AllowOrigins>
</CORS>

Example:
Flow variable

This example specifies a flow variable that represents one origin that is allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
</CORS>

Example:
Wildcard

This example specifies that all origins are allowed to access the resource.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>*</AllowOrigins>
</CORS>

<DisplayName>

Use in addition to the name attribute to label the policy in the management UI proxy editor with a different, more natural-sounding name.

The <DisplayName> element is common to all policies.

Default Value N/A
Required? Optional. If you omit <DisplayName>, the value of the policy's name attribute is used.
Type String
Parent Element <PolicyElement>
Child Elements None

The <DisplayName> element uses the following syntax:

Syntax

<PolicyElement>
  <DisplayName>POLICY_DISPLAY_NAME</DisplayName>
  ...
</PolicyElement>

Example

<PolicyElement>
  <DisplayName>My Validation Policy</DisplayName>
</PolicyElement>

The <DisplayName> element has no attributes or child elements.

<ExposeHeaders>

A list of HTTP headers that the browsers are allowed to access or an asterisk (*) to allow all HTTP headers. Serialized into the Access-Control-Expose-Headers header.

Default Value If not specified, Access-Control-Expose-Headers will not be set. Non-simple headers are not exposed by default.
Required? Optional
Type String, with message template* support
Parent Element <CORS>
Child Elements None

* For more information, see What is a message template?

The <ExposeHeaders> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <ExposeHeaders>[X-CUSTOM-HEADER-A, X-CUSTOM-HEADER-B, ... | *]</ExposeHeaders>
</CORS>

Example

This example specifies that the browsers are allowed to access all HTTP headers.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <ExposeHeaders>*</ExposeHeaders>
</CORS>

<GeneratePreflightResponse>

Indicate whether the policy should generate and return the CORS preflight response. If false, no response is sent. Instead, the following flow variables are populated:

  • cross_origin_resource_sharing.allow.credentials
  • cross_origin_resource_sharing.allow.headers
  • cross_origin_resource_sharing.allow.methods
  • cross_origin_resource_sharing.allow.origin
  • cross_origin_resource_sharing.allow.origins.list
  • cross_origin_resource_sharing.expose.headers
  • cross_origin_resource_sharing.max.age
  • cross_origin_resource_sharing.preflight.accepted
  • cross_origin_resource_sharing.request.headers
  • cross_origin_resource_sharing.request.method
  • cross_origin_resource_sharing.request.origin
  • cross_origin_resource_sharing.request.type
Default Value true
Required? Optional
Type Boolean
Parent Element <CORS>
Child Elements None

The <GeneratePreflightResponse> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <GeneratePreflightResponse>[false|true]</GeneratePreflightResponse>
  <GeneratePreflightResponse>[false|true]</GeneratePreflightResponse>
</CORS>

Example

This example specifies that the policy should generate and return the CORS preflight response.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <GeneratePreflightResponse>true</GeneratePreflightResponse>
</CORS>

<IgnoreUnresolvedVariables>

Determines whether processing stops when an unresolved variable is encountered. Set to true to ignore unresolved variables and continue processing; otherwise false.

Default Value true
Required? Optional
Type Boolean
Parent Element <CORS>
Child Elements None

The <IgnoreUnresolvedVariables> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <IgnoreUnresolvedVariables>[false|true]</IgnoreUnresolvedVariables>
</CORS>

Example

This example specifies that processing continues when an unresolved variable is encountered.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

<MaxAge>

Specifies how long the results of a preflight request can be cached in seconds. A value of -1 populates the Access-Control-Max-Age header with a value of -1, which disables caching, requiring a preflight OPTIONS check for all calls. This is defined in the Access-Control-Max-Age specification.

Default Value 1800
Required? Optional
Type Integer
Parent Element <CORS>
Child Elements None

The <MaxAge> element uses the following syntax:

Syntax

<CORS continueOnError="[false|true]" enabled="[false|true]" name="POLICY_NAME">
  <AllowOrigins>[{message template}|URL|URL, URL, ...|{context-variable}|{flow-variable}|*]</AllowOrigins>
  <MaxAge>[integer|-1]</MaxAge>
</CORS>

Example:
Cache

This example specifies that the results of a preflight request can be cached for 3628800 seconds.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <MaxAge>3628800</MaxAge>
</CORS>

Example:
No cache

This example specifies that the results of a preflight request cannot be cached.

<CORS continueOnError="false" enabled="true" name="add-cors">
  <AllowOrigins>{request.header.origin}</AllowOrigins>
  <MaxAge>-1</MaxAge>
</CORS>

Usage notes

OPTIONS requests

When an OPTIONS request is received and processed by the CORS policy, proxy flow execution transfers directly to the Proxy Response PreFlow, skipping the request flows entirely and continues execution from there. There is no need to create a Condition to ignore the OPTIONS request in the proxy request flow.

On subsequent calls, when the CORS policy executes, if the MaxAge set in the policy has not expired, the flow continues as normal. During the final response flow just before "Response Sent to Client," a special CORS execution step "CORSResponseOrErrorFlowExecution" sets CORS response headers (Access-Control-Allow-Credentials, Access-Control-Allow-Origin, and Access-Control-Expose-Headers) to return a CORS-validated response.

Error codes

This section describes the fault codes and error messages that are returned and fault variables that are set by Apigee when this policy triggers an error. This information is important to know if you are developing fault rules to handle faults. To learn more, see What you need to know about policy errors and Handling faults.

Runtime errors

These errors can occur when the policy executes.

Fault code HTTP status Cause
steps.cors.UnresolvedVariable 500 This error occurs if a variable specified in the CORS policy is either:
  • Out of scope (not available in the specific flow where the policy is being executed)
  • or

  • Can't be resolved (is not defined)

Deployment errors

These errors can occur when you deploy a proxy containing this policy.

Error name Cause
InvalidMaxAge MaxAge is not number
MissingAllowOrigins AllowOrigins is not specified
InvalidHTTPMethods One of the methods in AllowMethods is not valid
AllowHeadersSizeTooLarge The string size in AllowHeaders is too large.
ExposeHeadersSizeTooLarge The string size in ExposeHeaders is too large.

Fault variables

These variables are set when this policy triggers an error at runtime. For more information, see What you need to know about policy errors.

Variables Where Example
fault.name = "FAULT_NAME" FAULT_NAME is the name of the fault, as listed in the Runtime errors table above. The fault name is the last part of the fault code. fault.name Matches "UnresolveVariable"
cors.POLICY_NAME.failed POLICY_NAME is the user-specified name of the policy that threw the fault. cors.AddCORS.failed = true

Example error response

{
   "fault":{
      "detail":{
         "errorcode":"steps.cors.UnresolvedVariable"
      },
      "faultstring":"CORS[AddCORS]: unable to resolve variable wrong.var"
   }
}

Example fault rule

<FaultRule name="Add CORS Fault">
    <Step>
        <Name>Add-CORSCustomUnresolvedVariableErrorResponse</Name>
        <Condition>(fault.name Matches "UnresolvedVariable") </Condition>
    </Step>
    <Condition>(cors.Add-CORS.failed = true) </Condition>
</FaultRule>

Flow variables

A CorsFlowInfo FlowInfo object will be added and it will be available to trace.

Property Type Read/Write Description Scope begins
cross_origin_resource_sharing.allow.credentials Boolean Read/Write Value from <AllowCredentials> Proxy request
cross_origin_resource_sharing.allow.headers String Read/Write Value from <AllowHeaders> Proxy request
cross_origin_resource_sharing.allow.methods String Read/Write Value from <AllowMethods> Proxy request
cross_origin_resource_sharing.allow.origin String Read/Write The request origin that is allowed, empty if it is not in the allow list Proxy request
cross_origin_resource_sharing.allow.origins.list String Read/Write Value from <AllowOrigins> Proxy request
cross_origin_resource_sharing.expose.headers String Read/Write Value from <ExposeHeaders> Proxy request
cross_origin_resource_sharing.max.age Integer Read/Write Value from <MaxAge> Proxy request
cross_origin_resource_sharing.preflight.accepted Boolean Read/Write Indicates if preflight request is accepted Proxy request
cross_origin_resource_sharing.request.headers String Read/Write The value of request Access-Control-Request-Headers header Proxy request
cross_origin_resource_sharing.request.method String Read/Write The value of request Access-Control-Request-Method header Proxy request
cross_origin_resource_sharing.request.origin String Read/Write The same as request.header.origin Proxy request
cross_origin_resource_sharing.request.type String Read/Write

Type of CORS request. Possible values:

  • ACTUAL: A request which is not a preflight request
  • PRE_FLIGHT: A preflight request
Proxy request