grx

CORS & browsers

Configure browser CORS at the HTTP host layer around a grx GraphQL handler.

CORS is HTTP policy, not GraphQL execution. grx returns an http.Handler; configure CORS in the HTTP server or framework that owns that handler. This keeps preflight requests, credentials, and non-GraphQL routes in one host-level policy.

grx does not provide a CORS package. Use the middleware for your HTTP stack.

For a browser request, the host middleware must answer the OPTIONS preflight before GraphQL tries to parse a document. Allow only the origins, methods, and headers that the application needs. When credentials are enabled, return an explicit origin instead of * and configure the client to send credentials.

net/http

The rs/cors package wraps any http.Handler:

graphql, err := grx.NewServer(
	grx.WithSchema(graph.Schema()),
)
if err != nil {
	log.Fatal(err)
}

handler := cors.New(cors.Options{
	AllowedOrigins:   []string{"https://app.example.com"},
	AllowedMethods:   []string{"GET", "POST", "OPTIONS"},
	AllowedHeaders:   []string{"Content-Type", "Authorization"},
	AllowCredentials: true,
}).Handler(graphql)

log.Fatal(http.ListenAndServe(":4000", handler))

Fiber

Use Fiber's native CORS middleware and adapt the net/http GraphQL handler at the route boundary:

app := fiber.New()
app.Use(fibercors.New(fibercors.Config{
	AllowOrigins:     "https://app.example.com",
	AllowMethods:     "GET,POST,OPTIONS",
	AllowHeaders:     "Content-Type, Authorization",
	AllowCredentials: true,
}))
app.All("/graphql", adaptor.HTTPHandler(graphql))

log.Fatal(app.Listen(":4000"))

Gin

Use Gin's CORS middleware before mounting the adapted GraphQL handler:

router := gin.New()
router.Use(gincors.New(gincors.Config{
	AllowOrigins:     []string{"https://app.example.com"},
	AllowMethods:     []string{"GET", "POST", "OPTIONS"},
	AllowHeaders:     []string{"Content-Type", "Authorization"},
	AllowCredentials: true,
}))
router.Any("/graphql", gin.WrapH(graphql))

log.Fatal(router.Run(":4000"))

Chi

Chi uses ordinary net/http middleware, so the same CORS middleware can wrap the GraphQL handler or the whole router:

router := chi.NewRouter()
router.Use(cors.New(cors.Options{
	AllowedOrigins:   []string{"https://app.example.com"},
	AllowedMethods:   []string{"GET", "POST", "OPTIONS"},
	AllowedHeaders:   []string{"Content-Type", "Authorization"},
	AllowCredentials: true,
}).Handler)
router.Mount("/graphql", graphql)

log.Fatal(http.ListenAndServe(":4000", router))

Credentials and subscriptions

Use explicit origins when credentials are enabled. Browsers reject credentialed requests with Access-Control-Allow-Origin: *.

HTTP CORS does not replace WebSocket origin checks. Configure websocket.Config.CheckOrigin separately for WebSocket subscriptions.

The WebSocket check runs during the upgrade request. It is not controlled by the HTTP CORS middleware, even when both requests use the same URL.

See HTTP middleware for authentication, request IDs, and other host-level middleware.

Edit this page on GitHub

Last updated on

On this page