Featured image of post How CORS Works and Fixing Access Block Errors Featured image of post How CORS Works and Fixing Access Block Errors

How CORS Works and Fixing Access Block Errors

Understand preflight checks, origin checks, and backend settings like Access-Control-Allow-Origin to fix CORS.

Introduction

CORS (Cross-Origin Resource Sharing) is a browser security mechanism that controls how web pages from one origin can request resources from a different origin. When a frontend at https://app.example.com tries to fetch data from https://api.example.org, the browser enforces a same-origin policy by default. CORS provides a controlled way to relax this policy through HTTP headers. This article explains the complete CORS flow, preflight requests, and how to fix common access-block errors.


Same-Origin Policy

An origin is defined by the combination of scheme, host, and port:

URLOrigin
https://example.com/page1https://example.com
https://example.com/page2Same origin
http://example.com/page1Different origin (different scheme)
https://api.example.comDifferent origin (different host)
https://example.com:3000Different origin (different port)

The same-origin policy blocks reading cross-origin responses by default. This prevents malicious sites from stealing data from other origins.


Simple Requests vs Preflight Requests

CORS distinguishes between simple requests and requests that trigger a preflight.

A request is simple if it meets all these conditions:

  • Method: GET, HEAD, or POST
  • Content-Type: application/x-www-form-urlencoded, multipart/form-data, or text/plain
  • No custom headers

For simple requests, the browser sends the request directly and checks the response for CORS headers.

All other requests trigger a preflight — an OPTIONS request sent before the actual request:

OPTIONS /api/data HTTP/1.1
Host: api.example.org
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type, Authorization

The server must respond with appropriate CORS headers for the browser to proceed.


Core CORS Response Headers

The server controls CORS behavior through these response headers:

HeaderPurpose
Access-Control-Allow-OriginSpecifies which origins are permitted
Access-Control-Allow-MethodsLists allowed HTTP methods
Access-Control-Allow-HeadersLists allowed custom request headers
Access-Control-Allow-CredentialsWhether credentials (cookies) are allowed
Access-Control-Max-AgeHow long preflight results can be cached
Access-Control-Expose-HeadersWhich response headers are accessible

Example CORS response for a preflight:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

Wildcard vs Specific Origins

Using Access-Control-Allow-Origin: * allows any origin but has restrictions:

  • Cannot be used with Access-Control-Allow-Credentials: true
  • Should only be used for public, read-only APIs

For credentialed requests, you must specify exact origins:

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

If you need multiple allowed origins, the server must dynamically echo the requesting origin after validating it against a whitelist.


Handling Cookies with CORS

To include cookies in cross-origin requests, both client and server must opt in:

Client (JavaScript):

fetch('https://api.example.org/data', {
  credentials: 'include', // sends cookies
});

Server (response headers):

Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Credentials: true

Without credentials: 'include', cookies are never sent cross-origin.


Common CORS Errors and Solutions

Error MessageLikely CauseFix
No 'Access-Control-Allow-Origin' header presentMissing CORS headers on serverAdd Access-Control-Allow-Origin
CORS header 'Access-Control-Allow-Origin' mismatchOrigin not in allowed listValidate origin against whitelist
Credentials flag is 'true', but the header is '*'Wildcard with credentialsUse specific origin instead of *
Method PUT is not allowed by Access-Control-Allow-MethodsMethod not listedAdd PUT to allowed methods
Request header field X-Custom is not allowedCustom header not in Allow-HeadersAdd header to Access-Control-Allow-Headers

Server Configuration Examples

Express.js:

const cors = require('cors');
app.use(cors({
  origin: 'https://app.example.com',
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  credentials: true,
}));

Nginx:

add_header Access-Control-Allow-Origin "https://app.example.com";
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type";

Conclusion

CORS is a critical security layer that protects users while enabling legitimate cross-origin interactions. Understanding the difference between simple and preflight requests, knowing which headers to configure, and correctly handling credentials are essential skills for full-stack developers. By properly configuring your server’s CORS policy, you can maintain security without blocking valid cross-origin traffic.