Skip to content

CORS

CORS is a middleware that handles Cross-Origin Resource Sharing (CORS) requests. It allows you to specify which origins are permitted to access your resources, as well as which HTTP methods and headers are allowed.

This middleware is converted from Echo's CORS middleware

go
mcors "github.com/rakunlabs/ada/middleware/cors"

Add middleware to directly mux, group or handler; usually placed at the top of the middleware chain:

go
mcors.Middleware()

Configuration

You can configure the middleware using mcors.WithConfig() option.

go
mcors.Middleware(
    mcors.WithConfig(mcors.Cors{
        AllowOrigins:     []string{"https://example.com", "https://*.example.com"},
        AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},
        AllowHeaders:     []string{"Content-Type", "Authorization"},
        AllowCredentials: true,
        ExposeHeaders:    []string{"X-Custom-Header"},
        MaxAge:           3600,
    }),
)

Configuration Options

Options docs generated by AI.

AllowOrigins

Determines the value of the Access-Control-Allow-Origin response header. This header defines a list of origins that may access the resource.

  • Type: []string
  • Default: []string{"*"}
  • Supports wildcards: * (any characters) and ? (single character)

Examples:

go
// Allow all origins (default)
AllowOrigins: []string{"*"}

// Allow specific domains
AllowOrigins: []string{"https://example.com", "https://api.example.com"}

// Allow subdomains using wildcards
AllowOrigins: []string{"https://*.example.com"}

// Mix specific and wildcard patterns
AllowOrigins: []string{"https://example.com", "https://*.trusted.com"}

Security Warning

Use extreme caution when handling origins and carefully validate any logic. Remember that attackers may register hostile domain names. See Exploiting CORS Misconfigurations.

MDN Reference: Access-Control-Allow-Origin

AllowMethods

Determines the value of the Access-Control-Allow-Methods response header. This header specifies the list of methods allowed when accessing the resource in response to a preflight request.

  • Type: []string
  • Default: []string{"GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"}

Example:

go
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}

MDN Reference: Access-Control-Allow-Methods

AllowHeaders

Determines the value of the Access-Control-Allow-Headers response header. This header is used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

  • Type: []string
  • Default: []string{} (empty, will echo back requested headers)

Example:

go
AllowHeaders: []string{"Content-Type", "Authorization", "X-Request-ID"}

If left empty, the middleware will automatically allow headers requested by the client in the preflight request.

MDN Reference: Access-Control-Allow-Headers

AllowCredentials

Determines the value of the Access-Control-Allow-Credentials response header. This header indicates whether the response can be exposed when the credentials mode is true (cookies, authorization headers, or TLS client certificates).

  • Type: bool
  • Default: false

Example:

go
AllowCredentials: true

Security Warning

Avoid using AllowCredentials: true with AllowOrigins: []string{"*"}. This is a security vulnerability. See Exploiting CORS Misconfigurations.

MDN Reference: Access-Control-Allow-Credentials

UnsafeWildcardOriginWithAllowCredentials

⚠️ UNSAFE/INSECURE: Allows wildcard * origin to be used with AllowCredentials flag. When enabled, any origin is considered allowed and sent back to the client with the Access-Control-Allow-Origin header.

  • Type: bool
  • Default: false

Security Warning

This is INSECURE and potentially leads to cross-origin attacks. Only use this if you fully understand the security implications.

Example:

go
// NOT RECOMMENDED - Security Risk!
AllowOrigins:                                []string{"*"},
AllowCredentials:                            true,
UnsafeWildcardOriginWithAllowCredentials:   true,

ExposeHeaders

Determines the value of Access-Control-Expose-Headers, which defines a list of headers that clients are allowed to access from the response.

  • Type: []string
  • Default: []string{} (empty, header not set)

Example:

go
ExposeHeaders: []string{"X-Request-ID", "X-Response-Time"}

By default, only these CORS-safelisted response headers are exposed:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Use this option to expose additional headers.

MDN Reference: Access-Control-Expose-Headers

MaxAge

Determines the value of the Access-Control-Max-Age response header. This header indicates how long (in seconds) the results of a preflight request can be cached.

  • Type: int
  • Default: 0 (header not sent)
  • Negative value: Sends "0" which instructs browsers not to cache

Example:

go
MaxAge: 3600  // Cache preflight for 1 hour

MDN Reference: Access-Control-Max-Age

Complete Example

go
package main

import (
    "net/http"
    
    "github.com/rakunlabs/ada"
    mcors "github.com/rakunlabs/ada/middleware/cors"
)

func main() {
    mux := ada.New()
    
    // Add CORS middleware with full configuration
    mux.Use(mcors.Middleware(
        mcors.WithConfig(mcors.Cors{
            AllowOrigins:     []string{"https://example.com", "https://*.example.com"},
            AllowMethods:     []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodDelete},
            AllowHeaders:     []string{"Content-Type", "Authorization", "X-Request-ID"},
            AllowCredentials: true,
            ExposeHeaders:    []string{"X-Response-Time", "X-Request-ID"},
            MaxAge:           86400, // 24 hours
        }),
    ))
    
    mux.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.Write([]byte(`{"message": "CORS enabled!"}`))
    })
    
    http.ListenAndServe(":8080", mux)
}

Common Scenarios

Development Environment (Allow All)

go
mcors.Middleware(
    mcors.WithConfig(mcors.Cors{
        AllowOrigins: []string{"*"},
        AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
        AllowHeaders: []string{"*"},
    }),
)

Production with Specific Origins

go
mcors.Middleware(
    mcors.WithConfig(mcors.Cors{
        AllowOrigins:     []string{"https://app.example.com", "https://admin.example.com"},
        AllowMethods:     []string{"GET", "POST", "PUT", "DELETE"},
        AllowHeaders:     []string{"Content-Type", "Authorization"},
        AllowCredentials: true,
        MaxAge:           3600,
    }),
)

Allow Subdomains

go
mcors.Middleware(
    mcors.WithConfig(mcors.Cors{
        AllowOrigins:     []string{"https://*.example.com"},
        AllowCredentials: true,
        MaxAge:           7200,
    }),
)

How It Works

Preflight Requests

For complex requests, browsers send a preflight OPTIONS request before the actual request. The middleware handles these automatically:

  1. Browser sends OPTIONS request with:

    • Origin header
    • Access-Control-Request-Method header
    • Access-Control-Request-Headers header (optional)
  2. Middleware responds with appropriate CORS headers:

    • Access-Control-Allow-Origin
    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers
    • Access-Control-Max-Age
  3. If the preflight is successful, browser sends the actual request

Simple Requests

For simple requests (GET, HEAD, or POST with simple headers), no preflight is required. The middleware adds appropriate CORS headers directly to the response.

Wildcard Pattern Matching

The middleware supports wildcard patterns in AllowOrigins:

  • * - matches any number of characters
  • ? - matches a single character

Examples:

  • https://*.example.com - matches https://api.example.com, https://app.example.com, etc.
  • https://api-?.example.com - matches https://api-1.example.com, https://api-2.example.com, etc.

Patterns are converted to regular expressions internally for efficient matching.

Best Practices

  1. Be Specific: Avoid using * in production. List specific allowed origins.

  2. Credentials Security: Never combine AllowOrigins: ["*"] with AllowCredentials: true.

  3. Minimize Allowed Methods: Only allow HTTP methods that your API actually uses.

  4. Cache Preflight Results: Set MaxAge to reduce preflight requests and improve performance.

  5. Validate Origins Carefully: Remember that attackers can register malicious domains. Validate your origin patterns thoroughly.

  6. Use HTTPS: Always use HTTPS in production, especially when AllowCredentials is true.

Troubleshooting

CORS Error: Origin Not Allowed

Check that the origin in the browser request matches one of your AllowOrigins patterns exactly, including the protocol (https:// vs http://).

Credentials Request Failed

Ensure both conditions are met:

  • AllowCredentials: true in middleware configuration
  • Client-side request includes credentials: 'include' (fetch) or withCredentials: true (XMLHttpRequest)
  • Origin is explicitly listed (not *)

Preflight Request Returns 204 but Actual Request Fails

Verify that your server handler doesn't return errors for the actual request. The middleware only handles CORS headers; your handler must also work correctly.