Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers that controls how web pages in one domain can request and interact with resources in a different domain. When building APIs that need to be accessed by web applications hosted on different domains, proper CORS configuration is essential. You can learn more about CORS on MDN Web Docs.
Goa provides a powerful CORS plugin that makes it easy to define and implement CORS policies for your services. The plugin handles all the necessary HTTP headers and preflight requests automatically, allowing you to focus on defining your access policies.
To use CORS functionality in your Goa design, you’ll need to import both the CORS plugin and the standard Goa DSL packages:
import (
cors "goa.design/plugins/v3/cors/dsl"
. "goa.design/goa/v3/dsl"
)
CORS policies can be defined at two levels in your Goa design:
The CORS plugin provides several functions to configure various aspects of your CORS policy:
Origin
: Specifies allowed origins (domains) that can access your APIMethods
: Defines allowed HTTP methodsHeaders
: Specifies allowed HTTP headersExpose
: Lists headers that browsers are allowed to accessMaxAge
: Sets how long browsers should cache preflight request resultsCredentials
: Enables sending cookies and HTTP authentication informationHere’s an example showing different ways to configure CORS at the service level:
var _ = Service("calc", func() {
// Allow requests only from "localhost"
cors.Origin("localhost")
// Allow requests from any subdomain of domain.com
cors.Origin("*.domain.com", func() {
cors.Headers("X-Shared-Secret", "X-Api-Version")
cors.MaxAge(100)
cors.Credentials()
})
// Allow requests from any origin
cors.Origin("*")
// Allow requests from origins matching a regular expression
cors.Origin("/.*domain.*/", func() {
cors.Headers("*")
cors.Methods("GET", "POST")
cors.Expose("X-Time")
})
})
Here’s a complete example showing how to implement CORS at both API and service levels in a calculator service:
package design
import (
. "goa.design/goa/v3/dsl"
cors "goa.design/plugins/v3/cors/dsl"
)
var _ = API("calc", func() {
Title("CORS Example Calc API")
Description("This API demonstrates the use of the goa CORS plugin")
// API-level CORS policy
cors.Origin("http://127.0.0.1", func() {
cors.Headers("X-Shared-Secret")
cors.Methods("GET", "POST")
cors.Expose("X-Time")
cors.MaxAge(600)
cors.Credentials()
})
})
var _ = Service("calc", func() {
Description("The calc service exposes public endpoints that defines CORS policy.")
// Service-level CORS policy
cors.Origin("/.*localhost.*/", func() {
cors.Methods("GET", "POST")
cors.Expose("X-Time", "X-Api-Version")
cors.MaxAge(100)
})
Method("add", func() {
// ... Same as usual ...
})
})
When you enable the CORS plugin in your design, Goa automatically:
The plugin takes care of all the low-level CORS implementation details, allowing you to focus on defining your security policies at a high level using the DSL.