CORS policy

This pageapplies toApigee andApigee hybrid.

View Apigee Edge documentation.

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 thesame-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 toopt-in if they wish to provide cross-origin resource sharing.

One use case for CORS is the developer portal SmartDoc'sTry this API feature. For information, see Configuring your API proxy to support the Try this API panel.

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

Caution:

Implementing a CORS policy can relax the same-origin policy (SOP). If a proxy developer sets theAccess-Control-Allow-Origin header to allow all (*), it effectively disables the same-origin protection.

TheAllowOrigins field is a required policy element and the default should not be set to allow all (*). Policy developers should make cautious decisions before exposing their resources.

This policy is aStandard policy and can be deployed to any environment type. For information on policy types and availability with each environment type, seePolicy types.

<CORS> element

Defines the CORS policy.

Default ValueSeeDefault Policy tab, below
Required?Required
TypeComplex 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:

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><DisplayName>DISPLAY_NAME</DisplayName><AllowOrigins>[{messagetemplate}|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:

<CORScontinueOnError="false"enabled="true"name="add-cors"><DisplayName>AddCORS</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 newCORS 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:

AttributeDefaultRequired?Description
nameN/ARequired

The internal name of the policy. The value of thename 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.

continueOnErrorfalseOptionalSet tofalse to return an error when a policy fails. This is expected behavior for most policies. Set totrue to have flow execution continue even after a policy fails. See also:
enabledtrueOptionalSet totrue to enforce the policy. Set tofalse toturn off the policy. The policy will not be enforced even if it remains attached to a flow.
async  falseDeprecatedThis 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 theAccess-Control-Allow-Credentials header.

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

The<AllowCredentials> element uses the following syntax:

Syntax

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

Example

This example sets theAccess-Control-Allow-Credentials header tofalse. That is, the caller isnot 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 theAccess-Control-Allow-Headers header.

Default ValueOrigin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers
Required?Optional
TypeString, with message template* support
Parent Element<CORS>
Child Elements None
Tip: Apigee recommends adding no more than 50 values to<AllowHeaders>.

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

The<AllowHeaders> element uses the following syntax:

Syntax

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><AllowOrigins>[{messagetemplate}|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.

<CORScontinueOnError="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 beserialized into theAccess-Control-Allow-Methods header.

Default ValueGET, POST, HEAD, OPTIONS
Required?Optional
TypeString, 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

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><AllowOrigins>[{messagetemplate}|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 outgoingAccess-Control-Allow-Origin is set to the origin as provided by the client.

Default ValueN/A
Required?Required
TypeString, with message template* support
Parent Element<CORS>
Child Elements None
Tip: Apigee recommends adding no more than 50 values to<AllowOrigins>.

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

The<AllowOrigins> element uses the following syntax:

Syntax

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><AllowOrigins>[{messagetemplate}|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.

Note: You can also set a context variable in a message template to an asterisk (*).Caution: If a proxy developer sets theAccess-Control-Allow-Origin header to allow all (*), it effectively disables the same-origin protection. The default should not be set to allow all (*). Policy developers should make cautious decisions before exposing their resources.
<CORS continueOnError="false" enabled="true" name="add-cors"><AllowOrigins>*</AllowOrigins></CORS>

<DisplayName>

Use in addition to thename 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 ValueN/A
Required?Optional. If you omit<DisplayName>, the value of the policy'sname attribute is used.
TypeString
Parent Element <PolicyElement>
Child Elements None

The<DisplayName> element uses the following syntax:

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 theAccess-Control-Expose-Headers header.

Default ValueIf not specified,Access-Control-Expose-Headers will not be set. Non-simple headers are not exposed by default.
Required?Optional
TypeString, with message template* support
Parent Element<CORS>
Child Elements None
Tip: Apigee recommends adding no more than 50 values to<ExposeHeaders>.

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

The<ExposeHeaders> element uses the following syntax:

Syntax

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><AllowOrigins>[{messagetemplate}|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. Iffalse, no response is sent. Instead, the followingflow 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 Valuetrue
Required?Optional
TypeBoolean
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 totrue to ignore unresolved variables and continue processing; otherwisefalse.

Default Valuetrue
Required?Optional
TypeBoolean
Parent Element<CORS>
Child Elements None

The<IgnoreUnresolvedVariables> element uses the following syntax:

Syntax

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><AllowOrigins>[{messagetemplate}|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 theAccess-Control-Max-Age header with a value of-1, which disables caching, requiring a preflightOPTIONS check for all calls. This is defined in the Access-Control-Max-Age specification.

Default Value1800
Required?Optional
TypeInteger
Parent Element<CORS>
Child Elements None

The<MaxAge> element uses the following syntax:

Syntax

<CORScontinueOnError="[false|true]"enabled="[false|true]"name="POLICY_NAME"><AllowOrigins>[{messagetemplate}|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 for3628800 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 anOPTIONS 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 theMaxAge 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, andAccess-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 codeHTTP statusCause
steps.cors.UnresolvedVariable500This 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 nameCause
InvalidMaxAgeMaxAge is not number
MissingAllowOriginsAllowOrigins is not specified
InvalidHTTPMethodsOne of the methods inAllowMethods is not valid
AllowHeadersSizeTooLargeThe string size inAllowHeaders is too large.
ExposeHeadersSizeTooLargeThe string size inExposeHeaders 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.

Note : If<GeneratePreflightResponse> is set to true and an error occurs, the policy returns a response to the client immediately and the error flow is skipped. The following variables are not populated:
VariablesWhereExample
fault.name = "FAULT_NAME"FAULT_NAME is the name of the fault, as listed in theRuntime errors table above. The fault name is the last part of the fault code.fault.name Matches "UnresolveVariable"
cors.POLICY_NAME.failedPOLICY_NAME is the user-specified name of the policy that threw the fault.cors.AddCORS.failed = true

Example error response

Note: For error handling, the best practice is to trap the errorcode part of the error response. Do not rely on the text in the faultstring, because it could change.
{"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

ACorsFlowInfoFlowInfo object will be added and it will be available to trace.

PropertyTypeRead/WriteDescriptionScope begins
cross_origin_resource_sharing.allow.credentialsBooleanRead/WriteValue from<AllowCredentials>Proxy request
cross_origin_resource_sharing.allow.headersStringRead/WriteValue from<AllowHeaders>Proxy request
cross_origin_resource_sharing.allow.methodsStringRead/WriteValue from<AllowMethods>Proxy request
cross_origin_resource_sharing.allow.originStringRead/WriteThe request origin that is allowed, empty if it is not in the allow listProxy request
cross_origin_resource_sharing.allow.origins.listStringRead/WriteValue from<AllowOrigins>Proxy request
cross_origin_resource_sharing.expose.headersStringRead/WriteValue from<ExposeHeaders>Proxy request
cross_origin_resource_sharing.max.ageIntegerRead/WriteValue from<MaxAge>Proxy request
cross_origin_resource_sharing.preflight.acceptedBooleanRead/WriteIndicates if preflight request is acceptedProxy request
cross_origin_resource_sharing.request.headersStringRead/WriteThe value of requestAccess-Control-Request-Headers headerProxy request
cross_origin_resource_sharing.request.methodStringRead/WriteThe value of requestAccess-Control-Request-Method headerProxy request
cross_origin_resource_sharing.request.originStringRead/WriteThe same asrequest.header.originProxy request
cross_origin_resource_sharing.request.typeStringRead/Write

Type of CORS request. Possible values:

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

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.