skills/a6-plugin-cors/SKILL.md
Skill for configuring the Apache APISIX cors plugin via the a6 CLI. Covers Cross-Origin Resource Sharing setup on routes, allow_origins, allow_methods, allow_headers, credentials handling, regex origin matching, preflight caching, and common operational patterns.
npx skillsauth add moonming/a6 a6-plugin-corsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| allow_origins | string | No | "*" | Allowed origins. Comma-separated scheme://host:port. Use * for all (no credentials). Use ** to force-allow all (security risk). |
| allow_methods | string | No | "*" | Allowed HTTP methods. Comma-separated. Use * or ** same as origins. |
| allow_headers | string | No | "*" | Allowed request headers. Comma-separated. When **, echoes the request's Access-Control-Request-Headers. |
| expose_headers | string | No | — | Response headers exposed to browser. Comma-separated. Not set by default. |
| max_age | integer | No | 5 | Preflight cache duration in seconds. -1 disables caching. |
| allow_credential | boolean | No | false | Allow credentials (cookies, auth headers). If true, cannot use * for other fields. |
| allow_origins_by_regex | array[string] | No | — | Regex patterns to match origins dynamically |
| allow_origins_by_metadata | array[string] | No | — | Reference origins from plugin metadata |
| timing_allow_origins | string | No | — | Origins for Resource Timing API access |
| timing_allow_origins_by_regex | array[string] | No | — | Regex patterns for timing origins |
| Value | Meaning | With allow_credential: true? |
|-------|---------|-------------------------------|
| * | Allow all | ❌ Not allowed (CORS spec) |
| ** | Force allow all | ✅ Allowed but dangerous (CSRF risk) |
| Specific | Exact match | ✅ Allowed |
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
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
{
"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
{
"plugins": {
"cors": {
"allow_origins_by_regex": [
".*\\.example\\.com$",
".*\\.partner\\.net$",
"^https://localhost:[0-9]+$"
],
"allow_methods": "GET,POST",
"allow_credential": true
}
}
}
{
"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.
{
"plugins": {
"cors": {
"allow_origins": "*",
"expose_headers": "X-Request-Id,X-RateLimit-Limit,X-RateLimit-Remaining"
}
}
}
Without expose_headers, browsers only expose CORS-safelisted headers.
| Header | When Set |
|--------|----------|
| Access-Control-Allow-Origin | Always (matching origin or *) |
| Access-Control-Allow-Methods | Always |
| Access-Control-Allow-Headers | Always |
| Access-Control-Expose-Headers | Only if expose_headers configured |
| Access-Control-Max-Age | Always (preflight responses) |
| Access-Control-Allow-Credentials | Only if allow_credential: true |
| Timing-Allow-Origin | Only if timing_allow_origins configured |
| Symptom | Cause | Fix |
|---------|-------|-----|
| Browser CORS error despite plugin | allow_credential: true with allow_origins: "*" | Use specific origins or ** (risky) |
| Preflight fails but GET works | allow_methods missing the method | Add method to allow_methods |
| Custom header blocked | Header not in allow_headers | Add header to allow_headers |
| Can't read response header in JS | Header not in expose_headers | Add header to expose_headers |
| Regex not matching | Missing anchors or escaping | Use $ anchor and escape dots: \\. |
| Cookies not sent cross-origin | allow_credential is false | Set allow_credential: true with specific origins |
| Origin format rejected | Missing scheme | Use https://example.com not example.com |
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
tools
Core skill for working with the a6 CLI — the Apache APISIX command-line tool. Provides project conventions, command patterns, architecture overview, and development workflow. Load this skill when working on a6 source code, adding new commands, writing tests, or modifying any a6 component.
tools
Recipe skill for implementing multi-tenant API gateway patterns using the a6 CLI. Covers tenant isolation via Consumer Groups, host/path/header-based routing, per-tenant rate limiting, context forwarding with proxy-rewrite, and declarative config sync workflows for multi-tenant management.
tools
Recipe skill for configuring mutual TLS (mTLS) using the a6 CLI. Covers SSL certificate management, upstream mTLS to backend services, client certificate verification, and end-to-end mTLS setup from client through APISIX to upstream.
tools
Recipe skill for configuring upstream health checks using the a6 CLI. Covers active health checks (HTTP probing), passive health checks (response analysis), combining both, configuring healthy/unhealthy thresholds, and monitoring upstream node status.