Octopus
1.x
Open

Reading2 min
Updated31 Jul 2026
Sourcev1/middleware/cors.mdx

CORS

Octopus ships a complete Cross-Origin Resource Sharing (CORS) middleware (octopus_middleware::Cors) that handles preflight OPTIONS requests and adds Access-Control-* headers to responses. It is configured globally (top-level cors) with optional per-route overrides (routes[].cors).

Note

Setting the top-level cors block adds the CORS middleware to the request chain. Once enabled, a matched route's routes[].cors override (attached as the MatchedRouteCors request extension) replaces the global policy for that route. If no top-level cors block is configured, the middleware is not added — and per-route cors has no effect — so set a (possibly restrictive) global cors block to turn CORS handling on.

What the middleware does01

The Cors middleware:

  • Resolves an effective config: a per-route MatchedRouteCors override if present in request extensions, otherwise the global configured policy.

  • For OPTIONS preflight: returns 204 No Content with Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Max-Age, and (if enabled) Access-Control-Allow-Credentials.

  • For other requests: runs the inner chain, then adds Access-Control-Allow-Origin (and exposed-headers / credentials headers) to the response.

Origin handling

  • If allowed_origins contains "*" and credentials are not allowed, the response uses Access-Control-Allow-Origin: *.

  • If allowed_origins contains "*" and credentials are allowed, the request's own Origin is echoed back (since * is invalid with credentials).

  • Otherwise the request Origin is echoed only when it is in allowed_origins.

Configuration schema02

Global: top-level cors

Setting this block enables CORS handling for the whole gateway.

KeyTypeDefaultDescription
allowed_originslist<string>[]Allowed origins ("*" for any)
allowed_methodslist<string>[GET, POST, PUT, DELETE, OPTIONS]Allowed methods
allowed_headerslist<string>[]Allowed request headers
exposed_headerslist<string>[]Headers exposed to the browser
max_ageint (seconds)3600Preflight cache lifetime
allow_credentialsboolfalseAllow cookies / Authorization
cors:
  allowed_origins:
    - https://app.example.com
  allowed_methods: [GET, POST, PUT, DELETE, OPTIONS]
  allowed_headers: [Content-Type, Authorization]
  exposed_headers: [X-Request-ID]
  max_age: 3600
  allow_credentials: false

Per-route: routes[].cors

Overrides the global policy for a matched route (requires the global cors block to be set, which is what adds the middleware to the chain).

KeyTypeDefaultDescription
allowed_originslist<string>[]Allowed origins ("*" for any)
allowed_methodslist<string>[]Allowed HTTP methods
allowed_headerslist<string>[]Allowed request headers
allow_credentialsboolfalseAllow cookies / Authorization
max_ageint (seconds)3600Preflight cache lifetime
routes:
  - path: /api/*
    upstream: backend
    methods: [GET, POST, OPTIONS]
    cors:
      allowed_origins:
        - https://app.example.com
      allowed_methods: [GET, POST]
      allowed_headers: [Content-Type, Authorization]
      allow_credentials: true
      max_age: 3600