Skip to main content

a6-plugin-cors

Overview

The cors plugin manages Cross-Origin Resource Sharing headers on APISIX routes. It automatically handles preflight OPTIONS requests, sets Access-Control-* response headers, and supports wildcard, exact, and regex-based origin matching.

When to Use

  • Enable browser-based JavaScript access to your API from different origins
  • Configure credentialed cross-origin requests (cookies, auth headers)
  • Allow specific subdomains via regex patterns
  • Control preflight cache duration for performance

Plugin Configuration Reference (Route/Service)

FieldTypeRequiredDefaultDescription
allow_originsstringNo"*"Allowed origins. Comma-separated scheme://host:port. Use * for all (no credentials). Use ** to force-allow all (security risk).
allow_methodsstringNo"*"Allowed HTTP methods. Comma-separated. Use * or ** same as origins.
allow_headersstringNo"*"Allowed request headers. Comma-separated. When **, echoes the request's Access-Control-Request-Headers.
expose_headersstringNoResponse headers exposed to browser. Comma-separated. Not set by default.
max_ageintegerNo5Preflight cache duration in seconds. -1 disables caching.
allow_credentialbooleanNofalseAllow credentials (cookies, auth headers). If true, cannot use * for other fields.
allow_origins_by_regexarray[string]NoRegex patterns to match origins dynamically
allow_origins_by_metadataarray[string]NoReference origins from plugin metadata
timing_allow_originsstringNoOrigins for Resource Timing API access
timing_allow_origins_by_regexarray[string]NoRegex patterns for timing origins

Wildcard Rules

ValueMeaningWith allow_credential: true?
*Allow all❌ Not allowed (CORS spec)
**Force allow all✅ Allowed but dangerous (CSRF risk)
SpecificExact match✅ Allowed

Step-by-Step: Enable CORS on a Route

1. Basic CORS (public API, no credentials)

a6 route create -f - <<'EOF'
{
"id": "public-api",
"uri": "/api/*",
"plugins": {
"cors": {}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF

Response headers on all requests:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: *
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 5

2. CORS with credentials (specific origins)

a6 route create -f - <<'EOF'
{
"id": "credentialed-api",
"uri": "/api/*",
"plugins": {
"cors": {
"allow_origins": "https://app.example.com,https://admin.example.com",
"allow_methods": "GET,POST,PUT,DELETE,OPTIONS",
"allow_headers": "Content-Type,Authorization,X-Custom-Header",
"expose_headers": "X-Request-Id,X-Response-Time",
"max_age": 3600,
"allow_credential": true
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF

Common Patterns

Regex-based origin matching (all subdomains)

{
"plugins": {
"cors": {
"allow_origins_by_regex": [
".*\\.example\\.com$"
],
"allow_methods": "GET,POST,PUT,DELETE",
"allow_credential": true,
"max_age": 86400
}
}
}

Matches: https://app.example.com, https://staging.example.com Does not match: https://example.com, https://evil.com

Multiple domain groups with regex

{
"plugins": {
"cors": {
"allow_origins_by_regex": [
".*\\.example\\.com$",
".*\\.partner\\.net$",
"^https://localhost:[0-9]+$"
],
"allow_methods": "GET,POST",
"allow_credential": true
}
}
}

Long preflight cache

{
"plugins": {
"cors": {
"allow_origins": "https://app.example.com",
"max_age": 86400,
"allow_credential": true
}
}
}

Browser caches the preflight response for 24 hours, reducing OPTIONS requests.

Expose custom response headers

{
"plugins": {
"cors": {
"allow_origins": "*",
"expose_headers": "X-Request-Id,X-RateLimit-Limit,X-RateLimit-Remaining"
}
}
}

Without expose_headers, browsers only expose CORS-safelisted headers.

Response Headers Set by Plugin

HeaderWhen Set
Access-Control-Allow-OriginAlways (matching origin or *)
Access-Control-Allow-MethodsAlways
Access-Control-Allow-HeadersAlways
Access-Control-Expose-HeadersOnly if expose_headers configured
Access-Control-Max-AgeAlways (preflight responses)
Access-Control-Allow-CredentialsOnly if allow_credential: true
Timing-Allow-OriginOnly if timing_allow_origins configured

Troubleshooting

SymptomCauseFix
Browser CORS error despite pluginallow_credential: true with allow_origins: "*"Use specific origins or ** (risky)
Preflight fails but GET worksallow_methods missing the methodAdd method to allow_methods
Custom header blockedHeader not in allow_headersAdd header to allow_headers
Can't read response header in JSHeader not in expose_headersAdd header to expose_headers
Regex not matchingMissing anchors or escapingUse $ anchor and escape dots: \\.
Cookies not sent cross-originallow_credential is falseSet allow_credential: true with specific origins
Origin format rejectedMissing schemeUse https://example.com not example.com

Config Sync Example

version: "1"
routes:
- id: cors-api
uri: /api/*
plugins:
cors:
allow_origins: "https://app.example.com"
allow_methods: "GET,POST,PUT,DELETE,OPTIONS"
allow_headers: "Content-Type,Authorization"
expose_headers: "X-Request-Id"
max_age: 3600
allow_credential: true
upstream_id: api-upstream
upstreams:
- id: api-upstream
type: roundrobin
nodes:
"backend:8080": 1

This page is generated from a6-plugin-cors/SKILL.md in the api7/a6 repository. Browse all skills on the AI Agent Skills page.

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation