π What is CORS?
Cross-Origin Resource Sharing (CORS) is a browser security feature that controls how web applications request resources (APIs, images, fonts, etc.) from a different origin (domain, protocol or port).
π Example:
- Your React frontend runs at
http://localhost:3000
. - Your Go API runs at
http://localhost:8080
. - When React fetches data from Go API β this is a cross-origin request.
Without proper CORS setup, the browser blocks the request for security reasons.
βοΈ How Does CORS Work?
CORS works via HTTP headers exchanged between the browser and server.
1. Simple Requests
Happen when:
- Method is GET, POST or HEAD
- Headers are only "safe" ones (
Accept
,Content-Type
asapplication/x-www-form-urlencoded
,multipart/form-data
,text/plain
)
π Example:
GET /api/products HTTP/1.1
Origin: http://example-frontend.com
Server Response:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example-frontend.com
If the header matches β browser allows. Otherwise, request is blocked.
2. Preflight Requests
For non-simple requests (e.g., PUT
, DELETE
or custom headers), the browser sends a preflight request using OPTIONS
.
What is Preflight Request?
Not all requests go directly to the server. Sometimes, the browser first asks:
"Hey server, is it safe if I send this request?" - This is called a preflight request.
A preflight request is anOPTIONS
call that the browser automatically makes before the actual request, when:
- The HTTP method is not simple (
GET
,POST
,HEAD
).- The request has custom headers (e.g.,
Authorization
,X-Custom-Header
).- The Content-Type is not "safe" (
application/x-www-form-urlencoded
,multipart/form-data
,text/plain
).
π Example:
OPTIONS /api/products HTTP/1.1
Origin: http://example-frontend.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Server must respond with allowed methods/headers:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://example-frontend.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600
Then, the actual request (PUT/DELETE) is sent.
β Why is CORS Important?
- Protects Users: Prevents malicious sites from sending requests to other sites using your credentials (Cross-Site Request Forgery protection).
- Granular Control: You decide which origins, methods and headers are safe.
- Modern Requirement: Any modern web app with frontend + backend on different domains needs correct CORS setup.
β οΈ Common Issues Caused by CORS
1οΈβ£ Blocked by CORS Policy (No 'Access-Control-Allow-Origin' header)
- Server not configured to allow the frontend domain.
2οΈβ£ Credential Errors
- Cookies or tokens require:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://myapp.com
β Note: *
cannot be used when credentials are allowed.
3οΈβ£ Preflight Failures
- Backend doesnβt respond correctly to
OPTIONS
.
4οΈβ£ Wildcard Misuse
- Using
Access-Control-Allow-Origin: *
everywhere β insecure.
π οΈ Example: CORS in Go (Gin Framework)
import (
"github.com/gin-gonic/gin"
"github.com/gin-contrib/cors"
"time"
)
func main() {
r := gin.Default()
r.Use(cors.New(cors.Config{
AllowOrigins: []string{"http://localhost:3000", "https://myapp.com"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization"},
ExposeHeaders: []string{"Content-Length"},
AllowCredentials: true,
MaxAge: 12 * time.Hour,
}))
r.GET("/api/products", func(c *gin.Context) {
c.JSON(200, gin.H{"product": "Laptop"})
})
r.Run(":8080")
}
π This setup allows React (localhost:3000
) or production frontend to call your Go API.
π Real-World Examples
-
Frontend hosted on Netlify (
https://myapp.netlify.app
) calling backend on AWS EC2 (https://api.myapp.com
). - Without CORS β browser blocks requests.
- With proper CORS headers β smooth API calls.
π Best Practices
- β
Always restrict origins β never
*
for sensitive APIs. - β For multiple environments (dev/staging/prod), configure env-specific origins.
- β Handle preflight (OPTIONS) requests in backend properly.
- β
Use
Access-Control-Max-Age
to reduce repeated preflights. - β Avoid allowing unnecessary headers/methods.
- β Never rely only on CORS for security β also use authentication & rate limiting.
π Latest Info & Trends
CORS in Fetch API:
fetch(url, { mode: "cors", credentials: "include" })
must match backend CORS setup.Private Network Access (PNA):
Browsers now add extra preflights for requests to private networks (likehttp://192.168.x.x
).-
Proxies in Dev:
- React (
create-react-app
) usesproxy
inpackage.json
to bypass CORS in local dev. - In production β must fix at backend.
- React (
π― Final Thoughts
CORS might look like a βweird error messageβ at first, but itβs one of the most important browser security features.
If your frontend talks to your backend (different domain/port), you must configure CORS properly β otherwise, users face blocked requests.
π The key takeaway:
- Donβt just throw
*
inAccess-Control-Allow-Origin
. - Think carefully about which origins, headers and methods are safe.
- Set it once, document it and avoid long debugging sessions.
Top comments (0)