AJAX - Cross-Origin Resource Sharing (CORS) in Depth for AJAX

Cross-Origin Resource Sharing (CORS) is a security mechanism implemented by browsers to control how web applications running on one origin can request resources from another origin. An “origin” is defined by the combination of protocol, domain, and port. For example, http://example.com and https://example.com are considered different origins, as are http://example.com:3000 and http://example.com:5000.

1. Why CORS Exists

Browsers enforce a policy called the Same-Origin Policy (SOP), which restricts AJAX requests from one origin to another by default. This is done to prevent malicious websites from accessing sensitive data from another site where a user may already be authenticated.

CORS relaxes this restriction in a controlled way. It allows servers to explicitly specify which external origins are permitted to access their resources.

2. How CORS Works

CORS is enforced by the browser, not the server. The server only sends headers indicating what is allowed, and the browser decides whether to allow or block the request.

When an AJAX request is made to a different origin, the browser includes an Origin header in the request. The server then responds with specific CORS headers to indicate whether the request is permitted.

Example:

Request Header:

Origin: https://client-app.com

Response Header:

Access-Control-Allow-Origin: https://client-app.com

If the origin matches, the browser allows the response to be accessed. Otherwise, it blocks it.

3. Simple Requests vs Preflight Requests

CORS distinguishes between two types of requests:

a) Simple Requests

These are requests that meet certain conditions:

  • Use methods like GET, POST, or HEAD

  • Use only standard headers (like Accept, Content-Type with limited values)

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

b) Preflight Requests

For more complex operations, the browser sends a preliminary request called a “preflight” request using the OPTIONS method. This checks whether the actual request is safe to send.

Preflight request includes:

OPTIONS /api/data
Origin: https://client-app.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

Server response:

Access-Control-Allow-Origin: https://client-app.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

Only if the server अनुमति matches the request will the browser proceed with the actual AJAX call.

4. Important CORS Headers

  • Access-Control-Allow-Origin
    Specifies which origin is allowed. Can be a specific domain or * (all domains).

  • Access-Control-Allow-Methods
    Lists HTTP methods allowed (GET, POST, PUT, DELETE, etc.).

  • Access-Control-Allow-Headers
    Specifies which custom headers can be used in the request.

  • Access-Control-Allow-Credentials
    Indicates whether cookies or authentication data can be included.

  • Access-Control-Expose-Headers
    Lists headers that the browser is allowed to access from the response.

  • Access-Control-Max-Age
    Defines how long the preflight response can be cached.

5. Credentials and CORS

By default, browsers do not send cookies or authentication headers in cross-origin requests. To include credentials:

Client-side:

fetch(url, {
  credentials: 'include'
});

Server-side must include:

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

Note that * cannot be used with credentials; a specific origin must be defined.

6. Common CORS Issues in AJAX

  • Missing Access-Control-Allow-Origin header

  • Incorrect handling of preflight requests

  • Using * with credentials (not allowed)

  • Server not supporting OPTIONS method

  • Mismatched headers between request and allowed headers

These issues result in the browser blocking the response, even if the server processed the request successfully.

7. Security Considerations

CORS is not a security feature for the server; it is a browser-enforced policy. Servers must still implement proper authentication and authorization.

Important practices:

  • Avoid using Access-Control-Allow-Origin: * for sensitive APIs

  • Restrict allowed origins to trusted domains

  • Validate incoming requests on the server side

  • Use tokens (JWT, OAuth) instead of relying solely on cookies

8. Debugging CORS Problems

CORS errors appear in the browser console, not as standard HTTP errors. Developers should:

  • Inspect request and response headers in Developer Tools

  • Check if preflight requests are being sent and handled correctly

  • Verify that server headers match client request expectations

9. Real-World Usage in AJAX

In modern web applications, front-end and back-end are often hosted on different domains (for example, a React frontend and a REST API backend). CORS becomes essential to enable communication between them.

Without proper CORS configuration, AJAX calls using fetch or XMLHttpRequest will fail due to browser restrictions, even if the API is functioning correctly.

10. Summary

CORS is a critical concept for enabling secure cross-origin AJAX communication. It works through HTTP headers that define access rules, supports both simple and preflighted requests, and must be carefully configured to balance accessibility and security. Understanding how browsers enforce CORS and how servers respond to it is essential for building modern web applications that interact across domains.