Simplified Overview of Cross-Origin Resource Sharing

Yoma DanielYoma Daniel
9 min read

Introduction

Cross-Origin Resource Sharing (CORS) is simply a method or mechanism for integrating applications. This mechanism enables controlled access to resources or information located outside a specific domain. So, clients’ web applications in domain A can interact with clients’ web applications in domain B. It’s that simple! In this article, Ill discuss why Cross-Origin Resource Sharing is important, give a brief history of its ancestor the Same-Origin Policy, talk about how CORS works, and give a few best practices to adopt when carrying out CORS Let’s get started, shall we?

Why is CORS Important For Modern Web Applications?

If you’re an avid internet user like me, you may have experienced instances where your browser pulls photos or videos from a photo platform API or gets sounds from a sound platform API. Actions like that are why CORS is important. CORS is a mechanism that lets the client browser confirm the authorization of the request with third parties before transferring any data.

What is the Same-origin Policy?

I cannot emphasize the importance of CORS without giving a brief history of its precursor, the Same-Origin Policy. Developers followed the Same-Origin Policy at an earlier stage of the Internet. It enforced the rule that clients can only send requests to a resource that has the same origin as the client’s URL. The port, protocol, and hostname of the client’s URL must match the server it requests from. Here is an example to understand this concept: Let’s say you host your website at:

https://myreader.com:443

This is your origin, which includes:

The Protocol: https

  • The Hostname: myreader.com

  • The Port: 443

Now, according to the Same-Origin Policy, your JavaScript code running on https://myreader.com can only make requests to a server with the exact origin — that means it can fetch data from:

https://myreader.com:443/api/data

But if it tries to request something from:

…it will be blocked by the browser because of the Same-Origin Resource Sharing restrictions. The policy protects users from malicious scripts intending to steal data from other sites via their browser.

What can we understand from these examples?

Although the Same-Origin policy was very secure, it was too restrictive, and more approaches had to be developed. Developers needed an approach that was both secure and flexible, which led to the development of Cross-Origin Resource Sharing. So, how is Cross-Origin Resource Sharing the perfect approach?

  • For starters, CORS allows for different components hosted on different domains to communicate with each other. So web applications that need third-party features can access these API securely. That provides the flexibility that Same-Origin lacks.

  • CORS allows different components of an application that are hosted in seperate domains to communicate seamlessly.

  • Emphasizing again the flexibility that CORS provides, CORS reduces restrictions that come with the Same-origin Policy, allowing developers to have a list of domains that can access their resources, while maintaining high security.

  • CORS is flexible enough that developers can create responsive web applications with more features and functionality while maintaining seamlessness.

How Does CORS Work?

We understand that CORS is a mechanism that lets the client browser confirm the authorization of the request with third parties before transferring any data, but how does that happen? To understand how CORS works, we’ll have to learn about its components. The major components involved in CORS are the Origin, the Browser (Client-side), the preflight request, the CORS headers (Server-side response headers), the server, and the actual request.

  1. The Origin

  • The origin is a combination of the scheme (protocol), host (domain), and port. An example of an origin is https://myreader.com:645.

  • CORS gets triggered whenever a web page tries to access a resource from a different origin than its own.

  1. Browser (Client-side)

  • This is the web browser where the JavaScript runs. It enforces CORS rules based on the server’s response.

  • When a script in the browser makes a cross-origin HTTP request (like fetch() or XMLHttpRequest), the browser checks if it's allowed.

  • For "non-simple" requests (e.g., methods like PUT, or headers like Authorization), the browser first asks for permission by sending a preflight request using the OPTIONS method.

  1. Preflight Request

The preflight is an automatic OPTIONS request sent by the browser before the actual request. It asks the server for permission to proceed with the real request. This is especially important for requests that are not considered "simple," such as those using methods like PATCH or carrying custom headers. The preflight ensures that the server explicitly permits the cross-origin interaction.

  1. CORS Headers (Server-Side Response Headers)

The server responds to preflight and actual requests with specific headers that control access. These include:

  • Access-Control-Allow-Origin: It specifies which origins are allowed.

  • Access-Control-Allow-Methods: Lists the HTTP methods permitted.

  • Access-Control-Allow-Headers: It lists the request headers that can be used.

  • Access-Control-Allow-Credentials: It indicates whether credentials, such as cookies, are allowed.

  • Access-Control-Expose-Headers: It specifies headers exposed to the clients.

  • Access-Control-Max-Age: It defines how long the browser can cache the preflight response.

These headers form the backbone of CORS enforcement, and they must be configured properly to avoid errors.Server

The server evaluates the preflight request, checks the origin, method, and headers, and responds accordingly. It can choose to approve or deny access based on its CORS policy. A misconfigured server, such as one missing CORS headers, can unintentionally block legitimate requests or introduce security vulnerabilities if it’s too permissive.

  1. Actual Request

If the preflight request is approved (or wasn’t needed), the browser sends the actual request (e.g., GET, POST, PUT). The server must again respond with the correct CORS headers. If the browser doesn’t see the expected headers in the response, it will block access to the response data, even if the request itself succeeded.

To reiterate:

Let’s say a web page at https://clientsite.com wants to send a DELETE request to https://api.example.com.

Because it’s a cross-origin request with a non-simple method (DELETE), the browser steps in and automatically sends a preflight OPTIONS request to https://api.example.com.

This preflight request includes the origin and asks: “Am I allowed to make this kind of request?”

The server receives the preflight and responds with CORS headers like:

pgsqlCopy codeAccess-Control-Allow-Origin: https://clientsite.com  
Access-Control-Allow-Methods: DELETE, GET  
Access-Control-Allow-Headers: Authorization

The browser checks this response. If the origin and method are allowed, it proceeds to send the actual DELETE request.

The server then processes that request and includes the correct CORS headers again in its response.

The browser sees the Access-Control-Allow-Origin header and allows the JavaScript code to access the data.

But if the server skips or misconfigures those headers, the browser blocks access, even if the server responded successfully. All you get is a CORS error in the browser console, and your code can’t use the response.

Best Practices for CORS

You should practice the following when carrying out Cross-Origin Resource Sharing on your server:

  1. Use The Right HTTP Headers

By using the right headers, you can comply with CORS browser policies and avoid errors. The right headers to use are: Access-control-allow-origin, Access-control-allow-methods, and Access-control-allow-headers.

  1. Appropriately Define Your Access List

Have a comma-separated list to grant access to individual domains. Unless you want to make the API public, don’t use a wildcard because it may incur or create vulnerabilities. For instance, imagine you use a regular expression to allow any site ending in trusted-site.org. This would give access to app.trusted-site.org and blog.trusted-site.org as intended.

However, it could also accidentally allow access to a harmful domain like phishingtrusted-site.org, which is not actually part of your trusted group but still matches the pattern.

Instead of using a loose regular expression that matches any domain ending in trusted-site.org, it’s safer to list only the exact subdomains you trust. For example, you can check if the Origin matches either https://app.trusted-site.org or https://blog.trusted-site.org and allow access only to those. This way, you avoid unintentionally granting access to malicious domains like faketrusted-site.org, which may appear similar but are not part of your trusted network.

  1. Correct Configuration of the API Server

  • Set up your API server to include important CORS headers in its responses.

  • Set up back-end logic to create the correct CORS headers based on the request’s origin.

  • With the right CORS headers, you can configure the server to handle OPTIONS requests before the main request is made.

  1. Secure Your CORS Setup

To keep your app safe, avoid using * (wildcard) in CORS. Do this instead:

a. Allow only trusted domains to access your resources.

b. Check and clean all inputs to prevent malicious requests.

c. Review your CORS settings often** to catch mistakes or security gaps.

d. Use HTTPS to protect data in transit.

e. Add server-side protections, like:

  • Rate limiting

  • Checking the origin

  • Token-based authentication

If you’re using Node.js, use a CORS library (like the CORS npm package) to make setup easier and safer.

  1. Set Up a Proxy Server to Handle CORS

You can use a proxy server to forward requests between the browser and your API. It helps bypass CORS issues by making the request appear to be from the same origin. Here’s how you do it:

a. Pick a place to run your proxy, such as your computer or a cloud server.

b. Install and set up proxy software (e.g., NGINX, Node.js with http-proxy).

c. Configure the proxy to change request headers as needed.

d. Add security rules such as login or IP restrictions.

e. Test it to make sure it forwards requests properly.

f. Keep it updated and monitored for performance and safety.

  1. Avoid Using the Null Value in Your List

In some cases, such as file requests or requests from localhost, browsers may set the Origin header to null. However, you should avoid allowing null in your list of permitted origins, as doing so can pose security risks by potentially granting access to untrusted or unauthorized sources.

Conclusion

Cross-Origin Resource Sharing (CORS) may seem like just another technical concept, but it's a crucial part of how the modern web works. It bridges the gap between strict browser security (thanks to the Same-Origin Policy) and the flexibility that today’s dynamic, interconnected apps demand.

Think of CORS as a gatekeeper; it doesn’t open the door wide for everyone, but checks credentials at the door, asking: “Who are you, and should you get in?” This balance between security and functionality makes CORS so valuable. Without it, your favorite apps wouldn’t be able to pull data from different services or integrate cool features from third-party APIs.

Whether you're a backend developer configuring CORS headers or a frontend developer debugging CORS errors in the browser console, understanding how this mechanism works will save you time, frustration, and security headaches. So, as you build web applications, always remember: CORS is not just about permissions, it’s about building trust between different domains, safely and deliberately.

See you on the next one, dev! ✨💋🚀

13
Subscribe to my newsletter

Read articles from Yoma Daniel directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yoma Daniel
Yoma Daniel