Free & open · no paywall, ever

IntegrAuth Academy

Identity, security and practical AI — free, from zero. Byte-sized lessons, real diagrams, hands-on labs, zero fluff. Two programs, each with its own exam and certificate.

20 tracks 241 lessons 242 hands-on labs 230+ diagrams 100% free

English is hard? Your browser can translate this page into Tamil, Telugu, Kannada, Malayalam or Hindi. Tech words stay in English so you learn the real names.

How?
  • Chrome on phone: ⋮ menu → Translate
  • Chrome on computer: right-click → Translate to …
  • Edge: the translate icon in the address bar
Identity & API Security Track 6 · API Security
0/166 lessons read
API SECURITY · LESSON 8

CORS and browser-facing APIs

Maya's app runs at app.example.com and calls the API at api.example.com. The browser console says: "blocked by CORS policy." A teammate wants to "just allow everything". That would hand every website the keys to your users' accounts. Your goal: set up CORS safely.

Key points
  • A browser lets a page send a request to another origin, but not read the reply.
  • CORS is the server saying which origins may read.
  • Use a short, exact allowlist of origins. Never repeat back any origin with credentials.
  • CORS only works in browsers. It is not sign-in.
  • CSRF defenses protect requests that change data.

The wall that CORS opens a door in

Browsers enforce the same-origin policy. A script on one origin may send requests to another origin. But by default it cannot read the reply. An origin is the scheme, host and port together. So https://app.example.com and https://api.example.com are different origins, and so are http and https.

CORS (cross-origin resource sharing) lets the server opt in. It allows chosen other origins to read its replies. CORS does not add a restriction. It relaxes one.

Think of it like…

a hostel warden with a visitor list. Anyone may knock at the gate. The warden hands over the reply only to visitors on the list. CORS is that list. "Reflect any origin" is a warden who writes each visitor's name on the list as they arrive.

Simple requests and preflight

A simple request is sent straight to the server. Only reading the reply is gated. A request is simple only when all three are true. It uses GET, HEAD or POST. It sets only a short list of safe headers. If it has a body, the type is application/x-www-form-urlencoded, multipart/form-data or text/plain.

Anything else is preflighted. Examples: a PUT or DELETE; an Authorization header or a custom X- header; a JSON body with Content-Type: application/json.

A preflight is a separate OPTIONS request the browser sends first. It asks: "may I send this?" Only if the server's answer allows it does the browser send the real request.

Watch out

A simple request is still sent, and it can still change data. The browser blocks only the attacker's ability to read the reply. "CORS blocked it" does not mean "the request did not happen".

CSRF: the other half

CSRF (cross-site request forgery) is when a bad page makes the victim's browser fire a request at your API. The browser adds the victim's cookies by itself. A form-encoded POST is a simple request, so it goes through at once. The main brake is the SameSite cookie setting. It tells the browser not to attach the cookie to requests that another site started. Add checks on requests that change things. CORS decides who can read; SameSite and CSRF checks decide what can change.

The mistake that undoes it all

To use cookies across origins, the browser needs Access-Control-Allow-Credentials: true and an exact origin. The wildcard * is forbidden with credentials. So a team often writes code that repeats back whatever origin asked. Then any website a user visits can make the browser call your API with that user's cookies, and read the reply. Repeating back the origin with credentials is the same as allowing every origin.

The safe pattern is a short, exact allowlist. Compare the incoming Origin with known-good origins. If it matches, send back that one origin, and add Vary: Origin. If not, send no CORS headers. Match exactly. A "contains" check is a trap. example.com.evil.com and notexample.com both contain "example.com".

Safe APIorigin in allowlist?echo that one + VaryUnsafe APIreflects ANY origin+ Allow-Credentials: trueMaya's appapp.example.comon the list ✓Attacker's pageevil.examplereads Maya's data✓ only app.example.com can read✗ every site can read with the user's cookies
Figure — Allowlist, do not reflect. Repeating back only an approved origin keeps Maya's app working and walls off other sites. Repeating back any origin with credentials opens the API to every page the user visits.

What CORS is not

  • CORS is not sign-in. You still need tokens or sessions, and permission checks on every request.
  • CORS does nothing outside browsers. A script, bot or server ignores the headers. So a strict CORS policy does not stop scraping. Sign-in and rate limits do.
Go deeper: The reply headers that decide it
HeaderWhat it says
Access-Control-Allow-OriginWhich origin may read the reply: one origin, or *. It cannot list several. To support many, check the caller's origin against an allowlist and repeat it back.
Access-Control-Allow-Credentialstrue allows requests with credentials (cookies, HTTP authentication) and lets the script read their replies.
Access-Control-Allow-Methods / -HeadersWhich methods and headers the real request may use. A * for headers does not cover Authorization. Name it.
Access-Control-Expose-HeadersWhich reply headers the script may read.
Access-Control-Max-AgeHow long the browser may keep the preflight answer.

The preflight carries Access-Control-Request-Method and Access-Control-Request-Headers. The server answers with Access-Control-Allow-Methods and Access-Control-Allow-Headers.

Go deeper: The null origin, and SameSite sites

Some requests carry Origin: null, such as sandboxed iframes and data: documents. Any page can arrange to send it. So Access-Control-Allow-Origin: null is a wildcard in disguise. Do not use it.

A cross-origin request still reaches your server, so CSRF defenses stay your job. For SameSite, "site" means the registrable domain, so a sibling subdomain counts as the same site. See sessions, cookies and sign-out.

🧪 Interactive lab — enable JavaScript to play with this one.

🧪 Try it free

Read MDN's CORS guide. Open your browser's developer tools on a single-page app and watch the Network tab for OPTIONS preflight calls. Grade your own cookies' SameSite, HttpOnly and Secure flags with Cookie Check.