LearnThatStack Ace your next interview
API Design · question
Question 7 of 92

What is CORS and how do you handle it in APIs?

beginner
← All API Design questions
Re-explain
Visual ↓

Cross-Origin Resource Sharing (CORS) lets a server tell browsers which other origins may call it. By default a browser stops a page's script from reading another origin's responses, and CORS headers relax that rule in a controlled way.

An origin is the scheme, host and port together, so https://app.example.com and https://api.example.com are different origins. The server declares what it allows.

Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 3600

For a request that isn't simple, such as a PUT or one with an Authorization header, the browser first sends a preflight OPTIONS request. Access-Control-Max-Age lets the browser cache that answer.

Handle it with a CORS library rather than by hand.

  • Be specific with allowed origins, and don't use * for requests with credentials.
  • Validate the Origin header against an allowlist on the server.
  • CORS only guides browsers. Other clients ignore it, so it never replaces authentication.
Rewriting in plainer words…

This answer doesn't lend itself to a diagram - it reads best . No credits were charged.

Why there's no diagram: “”

The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓

The diagram below the answer is the concept . Jump to it ↓

Tailored explanation · switch back to · ·
What should the new diagram focus on?
Guided practice for API Design One question at a time. Answer out loud, get graded, see what you missed.
Related concept

The browser enforces CORS, not your server

The browser runs the same-origin policy to protect its users. And CORS headers tell the browser which origins may read the reply, but requests from curl, POSTMAN don't go through that check.

For this question · all 2 chaptersThe Access-Control headers in this answer are read by the browser's gate, never by your server. Watch the terminal's copy of the same GET land in full while the page's copy waits at the gate, then the preflight chapter: two lists the browser checks before a PUT ever leaves.

1/2 CORS is browser's check
CORSCORS is browser's checkthe browser guards its userBrowserapp.example.com200 ordersevil.exampleheldAPI serverAllow-Origin: app.example.comTerminal200 orders, in full600 s
CORSCORS is browser's checkBrowserapp.example.com200 ordersevil.exampleheldAPI serverAllow-Origin: app.example.comTerminal200 orders, in full600 s

CORS is browser's check

  1. Your call to the endpoint works from Postman, but the same call from your page fails with "blocked by CORS policy". Nothing is wrong with the server. An origin is three parts: scheme, host and port. Here app.example.com and api.example.com differ only in the host, so the browser blocks your page.
  2. This first request is a plain GET /orders. The browser adds an Origin header, which specify the page that made the call. The server answers 200 and sends the body back. The reply reaches the browser, but the browser refuses to hand that response to the page.
  3. The server writes the Access-Control-Allow-Origin header, and the browser reads that header as a pass. The header speicfy one allowed origin, https://app.example.com. The browser lets the response reach the page because the server specified that origin. The allow list comes from the server, but the browser checks the list and decides.
  4. A PUT with a JSON body and an Authorization header is not a simple request. So the browser asks the server first, with an OPTIONS preflight carrying Access-Control-Request-Method and Access-Control-Request-Headers. The server answers with Allow-Methods, Allow-Headers and Max-Age. Two things trigger that preflight: any method other than GET, HEAD or POST, and any header the browser does not already allow.
  5. The browser now sends the PUT request itself. The server answers with 200, and the response passes the browser's check. The second PUT sends no preflight OPTIONS request, because Max-Age told the browser to remember the answer for 600 seconds, per URL and per method. Your dev tools then show fewer OPTIONS calls than you expected.
  6. A terminal sends the same GET /orders request, and no browser is involved. Nothing enforces CORS here, so the full response body comes back. The CORS check never runs for curl, Postman, a cron job or another server, so CORS does not protect the API. Authentication protects the API, and CORS decides if a page inside a browser may read the response.
  7. The browser refuses a wildcard when credentials are involved. So many servers copy back whatever Origin the request sent, and add Allow-Credentials: true. A tab at evil.example sends GET /orders request, and the browser attaches the session cookie if that cookie is allowed cross-site. The browser's check reads the copied Origin and allows the read, so the untrusted page gets the user's orders.
  8. Allow one named origin again, so the browser blocks the evil tab from reading the reply. The terminal still receives the reply, as nothing about the terminal changed. Keep a real list of allowed origins, and return the single origin that matched. Send Vary: Origin as well, so a cache never gives one origin's permission to another.
Chapter 1 · step 1 of 8

Your call to the endpoint works from Postman, but the same call from your page fails with "blocked by CORS policy". Nothing is wrong with the server. An origin is three parts: scheme, host and port. Here app.example.com and api.example.com differ only in the host, so the browser blocks your page.

1 of 8 Use ← → or swipe See the concept

© LearnThatStack - diagrams may not be republished without permission.

How well did you know this?
AI:

Saved in this browser - sign in to keep your review list.

How should your speech become text?

Listening… your words appear above as you speak - tap Stop when you're done.

Recording · cr - tap Stop & transcribe when you're done.

Transcribing with AI…

Voice:

Keep going - a few more words and AI can grade it.

Interview lens How interviewers actually use this question

Likely follow-ups

  • Your API uses session cookies. What changes in the CORS setup so cross-origin calls work? Allow-Credentials: true, an exact origin instead of *, the client opting in to send credentials, and Vary: Origin when you echo the origin.
  • Does CORS protect your API from CSRF? Why or why not? Simple cross-origin requests still reach the server with cookies, and CORS only blocks reading the response. Name CSRF tokens or SameSite cookies instead.
  • Which requests skip the preflight, and why does a JSON POST still trigger one? Simple means GET, HEAD or POST with safelisted headers and a form or text/plain content type. application/json is not on that list.
  • The preflight succeeds but the browser still blocks the real response. Where do you look? The actual response needs Allow-Origin too. Check error paths, proxies or CDNs that drop the headers, and cached responses without Vary: Origin.
  • An API gateway sits in front of your services. Where should the CORS headers be set? Set them in one layer so responses don't carry duplicate or conflicting headers, and make sure auth checks don't reject the OPTIONS preflight.

What you can say

  1. CORS is how a server tells browsers which other origins may read its responses, relaxing the browser's default same-origin rule in a controlled way.
  2. An origin is the scheme, host and port together, so app.example.com and api.example.com count as different origins.
  3. The server declares what it allows with headers like Access-Control-Allow-Origin, Allow-Methods and Allow-Headers.
  4. For a request that isn't simple, like a PUT or one with an Authorization header, the browser sends a preflight OPTIONS request first, and Max-Age lets it cache that answer.
  5. In practice I use a CORS library, check the Origin header against an allowlist, and never use * when the request carries credentials.
  6. CORS only guides browsers, and curl or a backend service ignores it, so it never replaces authentication.

Weak answers to avoid

  • Treats CORS as server-side security CORS only binds browsers. Curl, scripts and other servers skip it, so say plainly that it never replaces authentication or authorization.
  • Reaches for * or echoes back any Origin A wildcard fails for requests with cookies, and reflecting any Origin with credentials lets any site read user data. Check Origin against an allowlist.
  • Thinks CORS stops the request reaching the server Simple requests still hit the server and run. The browser only hides the response from the page's script, which is why CORS is no CSRF defense.
  • Can't say when a preflight happens Saying the browser sends OPTIONS isn't enough. Name what triggers it, such as a PUT or an Authorization header, and how Max-Age cuts repeat preflights.
Interview lens

Likely follow-ups, what you can say, and the weak answers to avoid.

Sign in free to open it Free account - the lens opens as soon as you're back.

Want a quick review of the fundamentals? See the API Design cheatsheet.

← Back to all API Design questions
Pro · $10/mo

74 of 92 API Design answers are in Pro.

Full answers, code samples, and AI explanations that go simpler or deeper. Cancel anytime.

  • Full answers + code
  • AI explanations, simpler or deeper
  • 1,000 AI credits / month
  • Cancel anytime