REST API CORS

A developer builds a web page, calls an API from JavaScript, and sees a red error in the browser console about CORS. Almost every web developer meets this message. CORS stands for Cross-Origin Resource Sharing. It is a browser rule that decides when a page may read responses from a different website.

The Building Guard Picture

Imagine an office building with a guard at the front desk. A visitor from another company asks to enter. The guard checks a list that the building owner provided. Visitors on the list walk in, and everyone else waits outside. The browser plays the guard, and the API server owns the list.

What Is an Origin

An origin combines three parts: the scheme, the host, and the port.

https://shop.example.com:443
  │          │            │
scheme      host         port
Page OriginAPI OriginSame Origin
https://shop.example.comhttps://shop.example.comYes
https://shop.example.comhttps://api.example.comNo (different host)
https://shop.example.comhttp://shop.example.comNo (different scheme)
http://localhost:3000http://localhost:8080No (different port)

The browser blocks scripts from reading responses across origins unless the server grants permission.

Simple Requests

A simple GET request goes straight to the server. The browser adds an Origin header, and the server answers with an Access-Control-Allow-Origin header.

GET /products
Origin: https://shop.example.com

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://shop.example.com

The browser compares the two origins. A match lets the script read the response. A missing or different value blocks it.

Preflight Requests

Requests that use methods such as PUT or DELETE, or headers such as Authorization, trigger a preflight. The browser sends an OPTIONS request first to ask permission.

Browser ── OPTIONS /orders/5
           Origin: https://shop.example.com
           Access-Control-Request-Method: DELETE
           Access-Control-Request-Headers: authorization ──→ API Server

Browser ←── 204 No Content
            Access-Control-Allow-Origin: https://shop.example.com
            Access-Control-Allow-Methods: GET, DELETE
            Access-Control-Allow-Headers: authorization
            Access-Control-Max-Age: 600 ──────────────────── API Server

Browser ── DELETE /orders/5 ──→ API Server

The Max-Age value lets the browser remember the answer for 600 seconds and skip repeated preflights.

Key Response Headers

HeaderPurpose
Access-Control-Allow-OriginNames the allowed origin
Access-Control-Allow-MethodsLists allowed methods
Access-Control-Allow-HeadersLists allowed request headers
Access-Control-Allow-CredentialsAllows cookies and auth data
Access-Control-Max-AgeSets preflight cache time

Configuration Advice

  • Allow only the origins that need access, and keep the list short.
  • Use the wildcard * only for fully public data with no credentials.
  • Return the exact requesting origin from an allowlist when credentials are involved.
  • Send a Vary: Origin header so caches store one copy per origin.
  • Handle OPTIONS requests on every route that browsers call.

Credentials and Cookies

Browsers hide cookies from cross-origin requests by default. A page that needs cookies must set credentials: "include" in its fetch call, and the server must answer with Access-Control-Allow-Credentials: true and a specific origin value. Both sides must agree, or the browser drops the response.

Page script:   fetch(url, { credentials: "include" })
Server reply:  Access-Control-Allow-Origin: https://shop.example.com
               Access-Control-Allow-Credentials: true

Reading the Console Error

The browser console names the failed check. A message about a missing Allow-Origin header means the server sent no CORS headers. A message about a preflight failure means the OPTIONS request returned an error status or lacked the right headers. Read the exact wording before changing any code, because each message points to a different fix.

What CORS Does Not Do

CORS protects users inside browsers. It does not protect the API. Tools such as cURL and Postman ignore CORS completely, and any attacker can send direct requests. Authentication, authorization, and validation remain the real defenses.

Common Mistakes

Wildcard with Credentials

Browsers reject Access-Control-Allow-Origin: * when the request includes cookies. Name the exact origin instead.

Fixing the Error in the Frontend

Front-end code cannot cure a CORS error. The API server must send the correct headers.

Blocked OPTIONS Requests

An authentication layer that demands a token on OPTIONS requests breaks every preflight. Let OPTIONS pass before authentication runs.