Skip to main content

CORS Middleware

The CORS (Cross-Origin Resource Sharing) middleware handles cross-origin resource sharing, allowing you to control which domains can access your API resources.

Usage

Basic Usage

import (
"go-slim.dev/slim"
"go-slim.dev/slim/middleware"
)

func main() {
s := slim.New()

// Use default configuration
s.Use(middleware.CORS())

s.GET("/api/users", func(c slim.Context) error {
return c.JSON(200, map[string]string{"message": "Hello"})
})

s.Start(":8080")
}

Custom Configuration

s := slim.New()

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"https://example.com", "https://app.example.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Content-Type", "Authorization"},
AllowCredentials: true,
ExposeHeaders: []string{"X-Request-ID"},
MaxAge: 3600,
}))

Configuration Options

CORSConfig

type CORSConfig struct {
// AllowOrigins defines a list of origins that may access the resource
// Optional. Default value []string{"*"}
AllowOrigins []string

// AllowOriginFunc is a custom function to validate the origin
// If this option is set, AllowOrigins is ignored
// Optional
AllowOriginFunc func(origin string) (bool, error)

// AllowMethods defines a list methods allowed when accessing the resource
// Used in response to a preflight request
// Optional. Default value includes common methods
AllowMethods []string

// AllowHeaders defines a list of request headers that can be used
// Used in response to a preflight request
// Optional. Default value []string{}
AllowHeaders []string

// AllowCredentials indicates whether the response can be exposed
// when the credentials flag is true
// Optional. Default value false
AllowCredentials bool

// ExposeHeaders defines the whitelist headers that clients are allowed to access
// Optional. Default value []string{}
ExposeHeaders []string

// MaxAge indicates how long (in seconds) the results of a preflight
// request can be cached
// Optional. Default value 0
MaxAge int
}

Examples

1. Allow All Origins (Development)

s.Use(middleware.CORS())

The default configuration allows all origins (AllowOrigins: []string{"*"}), suitable for development environments.

2. Restrict Specific Domains

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{
"https://example.com",
"https://app.example.com",
},
}))

3. Use Wildcard Patterns

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{
"https://*.example.com", // Allow all subdomains of example.com
"http://localhost:*", // Allow localhost on all ports
},
}))

4. Custom Origin Validation Function

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOriginFunc: func(origin string) (bool, error) {
// Custom logic, e.g., query from database
allowedOrigins := []string{
"https://example.com",
"https://app.example.com",
}

for _, allowed := range allowedOrigins {
if origin == allowed {
return true, nil
}
}
return false, nil
},
}))

5. Support Credentials (Cookies)

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"https://example.com"},
AllowCredentials: true,
AllowHeaders: []string{"Content-Type", "Authorization"},
}))

Note: When AllowCredentials: true, AllowOrigins cannot be set to ["*"]. You must specify concrete domain names.

6. Complete Configuration Example

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{
"https://example.com",
"https://app.example.com",
},
AllowMethods: []string{
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
},
AllowHeaders: []string{
"Origin",
"Content-Type",
"Accept",
"Authorization",
"X-Request-ID",
},
ExposeHeaders: []string{
"X-Request-ID",
"X-Response-Time",
},
AllowCredentials: true,
MaxAge: 3600, // 1 hour
}))

How It Works

Simple Requests

For simple requests, the CORS middleware:

  1. Checks the Origin header
  2. Validates if the origin is in the allow list
  3. If allowed, sets the Access-Control-Allow-Origin response header
  4. If AllowCredentials is configured, sets the corresponding response header
  5. Continues processing the request

Preflight Requests

For preflight requests (HTTP OPTIONS), the CORS middleware:

  1. Checks the Origin header
  2. Validates if the origin is in the allow list
  3. Sets Access-Control-Allow-Origin
  4. Sets Access-Control-Allow-Methods
  5. Sets Access-Control-Allow-Headers
  6. If MaxAge is configured, sets Access-Control-Max-Age
  7. Returns 204 No Content status code

Default Configuration

CORSConfig{
AllowOrigins: []string{"*"},
AllowMethods: []string{
"GET",
"HEAD",
"PUT",
"PATCH",
"POST",
"DELETE",
},
AllowHeaders: []string{},
AllowCredentials: false,
ExposeHeaders: []string{},
MaxAge: 0,
}

Best Practices

1. Restrict Origins in Production

// Development environment
if os.Getenv("ENV") == "development" {
s.Use(middleware.CORS())
} else {
// Production environment
s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{
"https://yourdomain.com",
"https://app.yourdomain.com",
},
AllowCredentials: true,
}))
}

2. Use Environment Variables

allowedOrigins := strings.Split(os.Getenv("ALLOWED_ORIGINS"), ",")

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: allowedOrigins,
}))

3. Limit Exposed Headers

Only expose headers that clients actually need:

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
ExposeHeaders: []string{
"X-Request-ID",
"X-Total-Count", // May be needed for pagination
},
}))

4. Set Reasonable MaxAge

Setting a reasonable cache time can reduce the number of preflight requests:

s.Use(middleware.CORSWithConfig(middleware.CORSConfig{
MaxAge: 86400, // 24 hours
}))

Security Considerations

  1. Never use AllowOrigins: ["*"] in production - this allows any website to access your API

  2. Use AllowCredentials: true with caution - ensure you understand the security implications

  3. Limit AllowMethods - only allow necessary HTTP methods

  4. Limit AllowHeaders - only allow necessary request headers

  5. Use HTTPS - avoid transmitting sensitive information over insecure connections

Common Questions

Q: Why is my CORS request failing?

A: Check the following:

  • Is the CORS middleware properly configured on the server?
  • Does AllowOrigins include the client's domain?
  • If using credentials (Cookies), is AllowCredentials: true set?
  • Are AllowHeaders and AllowMethods correctly configured?

Q: What is a preflight request?

A: A preflight request is an OPTIONS request automatically sent by the browser before certain cross-origin requests to check if the server allows the actual request.

Q: Can AllowOrigins: ["*"] and AllowCredentials: true be used together?

A: No. For security reasons, when credentials are enabled, you must specify concrete origins, not the wildcard *.

References