CORS policy Stay organized with collections Save and categorize content based on your preferences.
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 Value | SeeDefault 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:
<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:
| Attribute | Default | Required? | Description |
|---|---|---|---|
name | N/A | Required | The internal name of the policy. The value of the Optionally, use the |
continueOnError | false | Optional | Set 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: |
enabled | true | Optional | Set 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 | 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 theAccess-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
<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 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 |
<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
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 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
<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 Value | N/A |
| Required? | Required |
| Type | String, with message template* support |
| Parent Element | <CORS> |
| Child Elements | None |
<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 Value | N/A |
| Required? | Optional. If you omit<DisplayName>, the value of the policy'sname 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 theAccess-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 |
<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.credentialscross_origin_resource_sharing.allow.headerscross_origin_resource_sharing.allow.methodscross_origin_resource_sharing.allow.origincross_origin_resource_sharing.allow.origins.listcross_origin_resource_sharing.expose.headerscross_origin_resource_sharing.max.agecross_origin_resource_sharing.preflight.acceptedcross_origin_resource_sharing.request.headerscross_origin_resource_sharing.request.methodcross_origin_resource_sharing.request.origincross_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 totrue to ignore unresolved variables and continue processing; otherwisefalse.
| Default Value | true |
| Required? | Optional |
| Type | Boolean |
| 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 Value | 1800 |
| Required? | Optional |
| Type | Integer |
| 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 code | HTTP status | Cause |
|---|---|---|
steps.cors.UnresolvedVariable | 500 | This error occurs if a variable specified in the CORS policy is either:
or |
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 inAllowMethods is not valid |
AllowHeadersSizeTooLarge | The string size inAllowHeaders is too large. |
ExposeHeadersSizeTooLarge | The 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:| Variables | Where | Example |
|---|---|---|
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.failed | POLICY_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.
| 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 requestAccess-Control-Request-Headers header | Proxy request |
cross_origin_resource_sharing.request.method | String | Read/Write | The value of requestAccess-Control-Request-Method header | Proxy request |
cross_origin_resource_sharing.request.origin | String | Read/Write | The same asrequest.header.origin | Proxy request |
cross_origin_resource_sharing.request.type | String | Read/Write | Type of CORS request. Possible values:
| 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.