We use analytics cookies.We use cookies to analyze site traffic and improve your experience.
Loading...
System Design Masterclass · Api Design Protocols
Free preview: the first 2 parts of this 7-part lesson.
Already bought the course? Sign in to read the whole lesson.
this lesson is part of
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design courseread the rest of this lesson in
System Design Masterclass
Unlock this lesson and the 751 other paid lessons
$25 once, by PayPal
See the System Design coursein Api Design Protocols
This lesson is part of the full System Design Masterclass. Unlock it along with 769 other lessons for a one-time payment.
One-time payment by card or PayPal
Get Lifetime AccessOne-time payment: UPI, card or netbanking
Get Lifetime Access18 Foundation lessons are free, no payment needed. Try them now
It is easy and good
“It is really nice and good Please join the course”
You build a frontend on localhost:3000. It calls your API at api.example.com. The request fails with a cryptic error:
Access to fetch at 'https://api.example.com/data' from origin
'http://localhost:3000' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the response.
Every frontend developer has stared at this error in confusion. The API works fine from Postman. It works from curl. It works from your backend. But the browser blocks it.
This isn't a bug, it's a security feature. Browsers enforce the Same-Origin Policy: a web page can only make requests to the same origin (protocol + domain + port) it was loaded from. Without this, a malicious page could read your bank's API responses using your cookies, steal your data, and transfer your money.
CORS (Cross-Origin Resource Sharing) is the controlled relaxation of this policy. It lets the server explicitly declare: "I allow requests from these specific origins." The browser asks the server for permission, and if granted, the request proceeds.
Simple requests (GET, HEAD, POST with standard content types) go directly to the server. The browser adds an Origin header, and the server responds with Access-Control-Allow-Origin:
Browser → Server:
GET /api/data
Origin: https://myapp.com
Server → Browser:
200 OK
Access-Control-Allow-Origin: https://myapp.com
{ "data": "..." }
If the Access-Control-Allow-Origin header is missing or doesn't match, the browser blocks the response. The server processed the request. CORS only blocks the browser from reading the response.
Preflight requests are required for "complex" requests (PUT, DELETE, custom headers, JSON content-type). Before the actual request, the browser sends an OPTIONS request asking for permission:
Browser → Server (preflight):
OPTIONS /api/orders
Origin: https://myapp.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
Server → Browser (preflight response):
204 No Content
Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400 ← cache this preflight for 24h
Browser → Server (actual request):
PUT /api/orders/123
Origin: https://myapp.com
Content-Type: application/json
Authorization: Bearer token123
Key CORS headers:
| Header | Purpose |
|---|---|
Access-Control-Allow-Origin | Which origins can access the resource |
Access-Control-Allow-Methods | Allowed methods (GET, POST, PUT...) |
Access-Control-Allow-Headers | Allowed request headers |
Access-Control-Allow-Credentials | Whether cookies/auth headers are allowed |
Access-Control-Max-Age | How long to cache the preflight response |
Access-Control-Expose-Headers | Which response headers the browser can read |