Skip to main content

cors

Adds CORS headers so browsers can call the API from other origins.

Category SecurityAdd it to Route, Service, Consumer, Consumer group, Global rule, Plugin configEngine plugin corsPriority 4000

What it does​

cors adds the headers a browser needs to let a page on another origin call your API. On the route, the origins go under Allow origins, with the methods and request headers they may use beside them. A request whose Origin is on the list is answered with that origin in Access-Control-Allow-Origin.

Allow credential lets browsers send cookies and authorization headers across origins, and then a * in any list is refused when you save. Switching it on alone is refused as well, because Allow origins, Allow methods and Allow headers read * until you name them.

When to use it​

  • A web app at https://app.example.com that calls the orders API from the browser with the user's session cookie.
  • Several storefront sites that share one list of origins, kept once in plugin metadata and picked by name on each route.
  • Preview sites, one subdomain each, admitted by one pattern under Allow origins by regex instead of a list that changes every week.
  • A response header the browser app must read, X-Request-Id for example, named under Expose headers.

Not for deciding which clients may call the API at all — see key-auth (Authenticates consumers with an API key sent in a header or query parameter) or refusing forged writes that ride on a browser's cookies — see csrf (Protects state-changing requests against cross-site request forgery).

Guides​

Pages that walk through a job with cors, step by step.

Set it up​

Let a browser app on another origin call the API with cookies​

Under Basics set Allow origins to https://app.example.com, turn on Allow credential, set Allow methods to GET,POST,PUT,DELETE and set Allow headers to Authorization,Content-Type. Under Behavior set Expose headers to X-Request-Id and set Preflight cache time to 3600 seconds.

The console's Add plugin panel, filled with this example.
cors · as the console saves it
{
"allow_origins": "https://app.example.com",
"allow_methods": "GET,POST,PUT,DELETE",
"allow_headers": "Authorization,Content-Type",
"allow_credential": true,
"expose_headers": "X-Request-Id",
"max_age": 3600
}

What you will see​

  • A request from the page at https://app.example.com is answered 200 with Access-Control-Allow-Origin: https://app.example.com, so the browser lets the page read the answer.
  • The same answer carries Access-Control-Allow-Credentials: true, so the browser sends the cookies of the API with the request and accepts the ones it sets.
  • The same answer carries Access-Control-Expose-Headers: X-Request-Id, so the page may read that header; every other header of the answer stays hidden from it.
  • The preflight the browser sends before a POST, an OPTIONS request naming the method it wants, is answered 200 by the gateway with Access-Control-Allow-Methods: GET,POST,PUT,DELETE.
  • The same preflight answer carries Access-Control-Allow-Headers: Authorization,Content-Type, the request headers the page may send.
  • The same preflight answer carries Access-Control-Max-Age: 3600, so the browser keeps the preflight answer for an hour and asks again only after that.

More scenarios​

Keep named sets of allowed origins that routes can pick by nameenvironment-wide settings

Fill Allow origins as in the JSON below.

cors environment-wide settings · as the console saves it
{
"allow_origins": {
"storefront": "https://shop.example.com,https://www.example.com",
"partners": "https://portal.partner.example.com"
}
}

What you will see​

  • On a route whose cors plugin names the set storefront, a request from https://shop.example.com is answered 200 with Access-Control-Allow-Origin: https://shop.example.com.
  • A request from https://www.example.com, the other origin of the same set, is answered 200 with Access-Control-Allow-Origin: https://www.example.com.

Things to know​

  • Allow origins — With https://app.example.com listed, a request from that origin is answered 200 with https://app.example.com in Access-Control-Allow-Origin.
  • Allow origins — An entry is a whole origin with its scheme; a.test is refused when you save.
  • Allow origins — ** admits any origin even with credentials, which opens the service to any site.
  • Allow credential — On, a request from a listed origin is answered with Access-Control-Allow-Credentials set to true beside its origin.
  • Allow credential — On by itself, it is refused when you save: the three lists of the first section read * until you name them, and a * is refused beside credentials.
  • Allow methods — An OPTIONS request from a listed origin is answered 200 with this list in Access-Control-Allow-Methods, GET,POST,PUT,DELETE in the example.
  • Expose headers — With Allow credential on, a * here is refused when you save as well. Name the headers one by one.
  • Allow origins by regex — A pattern that is not anchored matches anywhere in the origin. A matching origin is echoed back, credentials included, and Allow origins is then ignored.
  • Allow origins by metadata — Each name picks a set kept under Allow origins in the cors plugin metadata of the environment. With storefront holding two origins, a request from either is answered with its own origin in Access-Control-Allow-Origin.
  • Preflight cache time — Browsers cap the value at a ceiling of their own.
  • Allow headers — A preflight from a listed origin is answered with this list in Access-Control-Allow-Headers, Authorization,Content-Type in the example.
  • Preflight cache time — The preflight answer carries the value in Access-Control-Max-Age, 3600 in the example, so the browser asks again only after that many seconds.
  • Expose headers — An answer to a listed origin carries this list in Access-Control-Expose-Headers, X-Request-Id in the example, so the page's script may read those headers.
  • AdviceWhere cookies travel, list the origins of your own web apps by name and keep ** out of the route.

Settings​

The fields as the console shows them, section by section.

Basics​

Allow originsallow_originsstringdefault *

The origins allowed to call, comma separated, such as https://app.example.com, where * allows any origin without credentials. ** allows any origin even with credentials, which opens the service to any site.

pattern^(\*|\*\*|null|\w+://[^,]+(,\w+://[^,]+)*)$
Allow credentialallow_credentialbooleandefault false

Lets browsers send cookies and authorization headers across origins, and needs explicit origins, methods and headers because their star default is refused.

Allow methodsallow_methodsstringdefault *

The methods allowed across origins, comma separated, such as GET,POST, where * allows all of them without credentials. ** allows all of them even with credentials.

Allow headersallow_headersstringdefault *

The request headers allowed across origins, comma separated, such as Authorization,Content-Type, where * allows all without credentials. ** allows all of them even with credentials.

Behavior​

Allow origins by regexallow_origins_by_regexarray of strings

Regular expressions the request's origin must match, anchored with ^ and $, such as ^https://[a-z0-9-]+\.example\.com$. An unanchored pattern matches anywhere, so example\.com also admits https://example.com.evil.org. A matching origin is echoed back, credentials included, and Allow origins is then ignored.

at least 1 item; each 1 to 4096 characters
Expose headersexpose_headersstring

Response headers the browser may read across origins, comma separated, where empty exposes only the safe set.

example X-Request-Id,X-Trace-Id
Preflight cache timemax_ageintegerdefault 5

How long a browser may cache a preflight answer, where -1 turns that caching off. Browsers cap the value at a ceiling of their own.

in seconds

Advanced​

Allow origins by metadataallow_origins_by_metadataarray of strings

Names of origin lists kept in this plugin's environment-wide metadata, used as allowed origins.

at least 1 item; each 1 to 4096 characters
Timing allow originstiming_allow_originsstring

Origins that may read the response's timing details, comma separated, where * allows every origin without credentials. ** allows every origin even with credentials, which weakens the protection.

pattern^(\*|\*\*|null|\w+://[^,]+(,\w+://[^,]+)*)$
Timing allow origins by regextiming_allow_origins_by_regexarray of strings

Regular expressions matched against the origin, one per entry, where a match may read the response's timing details.

at least 1 item; each 1 to 4096 characters

Environment-wide settings​

Set once per environment, under Plugins › cors. Every cors in the environment uses these.

Allow originsallow_originsobject

An object whose keys are any name, each with a string as its value.

Every plugin also has Enabled, Priority, Filter, Error response and Pre-function: see Plugin execution settings.

G8 dev · Apache APISIX® 3.19.0
Apache, Apache APISIX and APISIX are trademarks of The Apache Software Foundation.
Facts
Category
Security
Add it to
Route, Service, Consumer, Consumer group, Global rule, Plugin config
Engine plugin
cors
Priority
4000