How to Configure CORS Settings for Cross-Origin Requests in AxonHub
AxonHub enables cross-origin resource sharing (CORS) through a declarative configuration block under server.cors, which activates Gin's CORS middleware when enabled: true and validates that allowed_origins is non-empty at startup.
AxonHub is an open-source platform built on the Gin web framework that handles HTTP traffic for event-driven architectures. To configure CORS settings for cross-origin requests, administrators modify Viper-backed configuration files or environment variables that populate the CORS struct defined in the server's configuration schema.
Understanding AxonHub's CORS Architecture
AxonHub implements CORS using the gin-contrib/cors middleware. The configuration lifecycle follows three distinct stages: default value definition in conf/conf.go, runtime validation in cmd/axonhub/main.go, and middleware registration in internal/server/routes.go. This separation ensures that invalid CORS configurations fail fast during application startup rather than at runtime.
Configuration Schema and Default Values
The CORS configuration struct is initialized with secure defaults in [conf/conf.go](https://github.com/looplj/axonhub/blob/unstable/conf/conf.go#L42-L52). The relevant fields include:
- enabled – Boolean toggle to activate the middleware (default:
false). - debug – Enables verbose CORS logging for troubleshooting (default:
false). - allowed_origins – Slice of permitted origin domains (default: empty).
- allowed_methods – HTTP methods allowed for cross-origin requests (default:
["GET", "POST", "PUT", "PATCH", "DELETE"]). - allowed_headers – Headers browsers may send (default:
["Origin", "Content-Type", "Accept", "Authorization"]). - exposed_headers – Response headers exposed to the client (default: empty).
- allow_credentials – Whether to expose cookies and authorization headers (default:
true). - max_age – Duration string for preflight cache (default:
"12h").
Enabling CORS Middleware
When the server initializes its Gin engine in [internal/server/routes.go](https://github.com/looplj/axonhub/blob/unstable/internal/server/routes.go#L59-L72), it checks server.Config.CORS.Enabled. If true, it constructs a cors.Config object mapping the configuration fields to the middleware options and registers it globally using server.Use(cors.New(corsConfig)). Additionally, an explicit server.OPTIONS("*any", corsHandler) route handles preflight requests for all endpoints.
Validation and Startup Checks
To prevent runtime misconfigurations, [cmd/axonhub/main.go](https://github.com/looplj/axonhub/blob/unstable/cmd/axonhub/main.go#L14-L16) validates that allowed_origins contains at least one entry when CORS is enabled. If validation fails, the application exits immediately with a descriptive error message, ensuring that cross-origin policies are explicitly defined before the server accepts traffic.
Practical Configuration Examples
YAML Configuration File
Create or modify config.yml in the working directory:
server:
cors:
enabled: true
debug: false
allowed_origins:
- "https://app.example.com"
- "https://admin.example.com"
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowed_headers:
- Origin
- Content-Type
- Accept
- Authorization
- X-Request-ID
exposed_headers:
- X-Request-ID
allow_credentials: true
max_age: "24h"
Environment Variables
For containerized deployments, export variables following the Viper convention (replace dots with underscores and uppercase):
export SERVER_CORS_ENABLED=true
export SERVER_CORS_ALLOWED_ORIGINS='["https://app.example.com","http://localhost:3000"]'
export SERVER_CORS_ALLOW_CREDENTIALS=true
export SERVER_CORS_MAX_AGE="12h"
axonhub # start the server
Programmatic Access (Go)
If you need to inspect the loaded configuration within a plugin or extension:
package main
import (
"fmt"
"github.com/looplj/axonhub/conf"
)
func main() {
cfg, err := conf.Load()
if err != nil {
panic(err)
}
if cfg.APIServer.CORS.Enabled {
fmt.Printf("CORS enabled for origins: %v\n", cfg.APIServer.CORS.AllowedOrigins)
}
}
Summary
- AxonHub’s CORS behavior is controlled by the
server.corsconfiguration block defined in [conf/conf.go](https://github.com/looplj/axonhub/blob/unstable/conf/conf.go#L42-L52). - The middleware is registered in [
internal/server/routes.go](https://github.com/looplj/axonhub/blob/unstable/internal/server/routes.go#L59-L72) only whenenabled: true. - Startup validation in [
cmd/axonhub/main.go](https://github.com/looplj/axonhub/blob/unstable/cmd/axonhub/main.go#L14-L16) ensuresallowed_originsis populated before the server starts. - You can configure CORS via YAML, environment variables, or programmatically using Viper-backed settings.
Frequently Asked Questions
What happens if I enable CORS but leave allowed_origins empty?
The application will exit immediately during startup with a validation error. The check in [cmd/axonhub/main.go](https://github.com/looplj/axonhub/blob/unstable/cmd/axonhub/main.go#L14-L16) requires at least one origin when CORS is enabled to prevent accidental open CORS policies.
Can I use wildcards in allowed_origins?
The underlying gin-contrib/cors library supports the wildcard "*" to allow any origin, but this is discouraged for production environments that use credentials. AxonHub’s configuration accepts the standard string slice, so you can include "*" as an element, but ensure allow_credentials is set to false when doing so.
How do I debug CORS issues?
Set server.cors.debug: true in your configuration file or SERVER_CORS_DEBUG=true as an environment variable. This enables verbose logging from the Gin CORS middleware, printing allowed origins, methods, and headers to the console for every preflight and actual request.
Does AxonHub support dynamic CORS configuration without restarting?
Currently, the CORS configuration is loaded once at startup via Viper and passed to the Gin engine during route initialization. Changing CORS settings requires a server restart to re-read the configuration file or environment variables. For dynamic updates, you would need to implement a custom middleware that reads from a hot-reloadable source.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →