Ugacomp

A beginner’s Guide to Cross-origin Resource Sharing (CORS)

Where necessary, you may need to have access to a VPS server so you can follow how to implement the steps in this article.  You can get a cheaper VPS Server from Contabo with 4vCPU cores, 8GM RAM, and 32TB Bandwidth for less than $5.50 per month. Get this deal here now

Table of Contents

Cloud VPS S

$5.50 Monthly
  • 4 vCPU Cores | 8GB RAM

CLOUD VPS M

$15.50 Monthly
  • 6 vCPU Cores | 16GB RAM

CLOUD VPS L

$17.50 Monthly
  • 8 vCPU Cores | 24GB RAM

Cross-origin resource sharing (CORS) is a security mechanism that allows a web page to make requests to a different domain than the one that served the web page. CORS works by adding HTTP headers to the response from the server that allows the browser to know that it is safe to allow the request to go through.

CORS ensures that web pages can only request resources from the same origin (port. domain, scheme) unless explicitly permitted by the server hosting those resources. It helps maintain the security and integrity of web applications while allowing controlled access to resources across different origins.

How does Cross-Origin Resource Sharing (CORS) work?

Imagine you’re planning a party (your website) and you want to invite guests (resources) from different neighborhoods (domains). However, you want to make sure your guests won’t cause any trouble or bring unexpected things to your party. That’s where CORS (Cross-Origin Resource Sharing) comes into play.

In the world of web development, browsers have this security feature that prevents a web page in one domain from making requests to a different domain. CORS is like the bouncer at your party checking invitations.

Web browsers implement a security feature known as the “Same-Origin Policy,” which restricts web pages from making requests to a different domain than the one that served the web page. CORS relaxes these security restrictions, allowing controlled access to resources across different origins while still maintaining security.

When your web page makes a cross-origin request (for example, using JavaScript to fetch data from a different website), the browser sends an HTTP request to the target server. The server can include special HTTP headers in its response, indicating which origins are allowed to access its resources.

If the server allows the request (based on the provided headers), the browser lets your web page access the requested resources. If the server doesn’t permit the request, the browser blocks the access, protecting the user’s data and preventing potential security risks.

Simple Requests

Simple requests involve basic stuff like GET, POST, and HEAD methods. If you’re asking for data or sending a bit of info, it’s usually straightforward.

Simple Requests don’t need preflight checks. This is because these requests are considered to be safe and do not pose a security threat to the server. To qualify as a simple request, a request must meet the following criteria:

  • Method: The request method must be one of the following HTTP methods: GET, HEAD, POST, PUT, or DELETE.

  • Headers: The request headers must be restricted to a list of allowed headers.

  • Content type: The request content type must be one of the following: application/x-www-form-urlencoded, multipart/form-data, or text/plain.

If a CORS request meets all of these criteria, then it will be considered a simple request and will not require a preflight check. This can save time and improve performance, as the preflight request is not necessary for simple requests.

How does Simple CORS request work?

You can have content hosted at server.ugacomp.com and want it to interact with or make requests to content hosted on another domain like example.com. If it’s a JavaScript application, the code at server.ugacomp.com to represent this interaction will be as seen below:

const xhr = new XMLHttpRequest();
const url = "https://example.com/resources/public-data/";

xhr.open("GET", url);
xhr.onreadystatechange = someHandler;
xhr.send();

This code implements a simple exchange between the client and the server using CORS headers to handle the privileges.

So, the GET request from the browser will be as seen below:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://server.ugacom.com

The server will give you the following Response:

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[…XML Data…]

The server at server.ugacomp.com will return an Access-Control-Allow-Origin header with Access-Control-Allow-Origin: *, meaning its resources can be accessed by any origin.

Access-Control-Allow-Origin: *

However, If the system admins at https://example.com wanted to prevent access to their server’s resources to only requests from https://system.ugacomp.com or any other domain name, then the Access-Control-Allow-Origin header response will be defined as seen below:

Access-Control-Allow-Origin: https://system.ugacomp.com

This kind of interaction and pattern of the Origin and Access-Control-Allow-Origin headers represent the easiest and simplest use of the access control protocol. 

Preflight Requests

Imagine you want to invite a special guest from another neighborhood, and this guest has some unique requirements (custom headers or HTTP methods) for attending your party. Before you officially invite them, you send a “preflight” invitation to ask if they’re okay with your party rules.

In technical terms, a preflight request is an extra step that some web browsers take before the actual request. It’s like sending a polite message (an HTTP OPTIONS request) to the server, asking, “Hey, can my website make this specific type of request to your domain?”

If the server responds with the right permissions (via headers like Access-Control-Allow-Origin), the browser knows it’s okay to send the actual request, and your special guest can come to the party.

Preflight requests require extra steps, making them more complex. These requests have their custom headers that don’t include GET or POST as we see we’ve seen in the Simple Requests.

How does Preflight CORS request work?

The instance below generates an XML for transmission in conjunction with a POST request. Additionally, a non-conventional HTTP X-PINGOTHER request header is established. While these headers fall outside the standard specifications of HTTP/1.1, they commonly prove beneficial for web applications. Given the request employs a Content-Type of text/xml and introduces a customized header, it undergoes a preflight process.

const xhr = new XMLHttpRequest();
xhr.open("POST", "https://bar.other/doc");
xhr.setRequestHeader("X-PINGOTHER", "pingpong");
xhr.setRequestHeader("Content-Type", "text/xml");
xhr.onreadystatechange = handler;
xhr.send("<person><name>Arun</name></person>");

Based on the above code, here is how the full exchange between client and server happens.

OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://system.ugacomp.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://system.ugacomp.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive

This code snippet triggers a preflight request using the OPTIONS method. This request conveys the request parameters to the server, allowing it to assess whether the actual request, including those specific parameters, is acceptable. It’s crucial to remember that the OPTIONS method is a safe HTTP/1.1 method designed solely for information gathering and cannot alter any resources.

You will also notice that two other request headers on lines 9 and 10 in the code snippet above are sent respectively):

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

These two request headers are necessary for this interaction. For example,

  • During a preflight request, the Access-Control-Request-Method header informs the server that the actual request, once sent, will utilize the POST method as its HTTP request method. This allows the server to verify whether it can accept such a request and prepare accordingly.

  • During a preflight request, the Access-Control-Request-Headers header informs the server about the custom headers, like X-PINGOTHER and Content-Type, which will be included in the actual request. This allows the server to pre-emptively assess whether the request can be accepted under those conditions.

In response, the server sends the Access-Control-Allow-Origin header, specifying https://system.ugacom.com as the only permitted origin for accessing the resource. Additionally, it includes the Access-Control-Allow-Methods header, limiting valid HTTP methods for interacting with the resource to POST and GET. This header bears resemblance to the Allow header but operates specifically within the context of access control.

The server further transmits the Access-Control-Allow-Headers header, declaring “X-PINGOTHER” and “Content-Type” as acceptable headers for inclusion in the actual request. Similar to Access-Control-Allow-Methods, this header utilizes a comma-separated list to enumerate authorized headers.

Access-Control-Allow-Origin: https://system.ugacomp.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

The server also transmits the Access-Control-Max-Age header, specifying the duration, in seconds, that the preflight response can be cached before a new preflight request is necessary. This value defaults to 5 seconds, but in this instance, the maximum age is set to 86400 seconds (24 hours). Be mindful that individual browsers possess internal maximum values that supersede the Access-Control-Max-Age when exceeded.

Once the preflight request is complete, the real request is sent:

To set up CORS in Nginx, you will need to follow the following steps:

POST /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://system.ugacomp.com/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache

<person><name>Arun</name></person>

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://system.ugacomp.com
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some XML payload]

CORS Use Cases

You can use CORS to handle various issues in the application and these are some of them:

Fix loading issues with Fonts in CSS declaration

If you have a custom font like  @font-face from a different origin and you want to use it in your CSS declaration, you will have to whitelist cross-origin access just for font files. So, what you need is to create a .htaccess file in the folder where the font files are stored and then add the following lines:

# Allow font assets to be used across domains and subdomains
<FilesMatch "\.(ttf|otf|eot|woff)$">
  <IfModule mod_headers.c>
    Header set Access-Control-Allow-Origin "*"
  </IfModule>
</FilesMatch>

Fix JavaScript Errors in the Control Panel

If you encounter JavaScript errors within the ExpressionEngine control panel, and upon investigation, discover that specific resources are not loading due to a cross-origin policy issue, you need to add appropriate headers to grant access to those resources. For example;

  • An addon named Example is attempting to make an Ajax request to the themes folder. However, due to Cross-Origin Resource Sharing (CORS) restrictions, this request is being blocked.
  • The ExpressionEngine control panel operates on a separate domain: https://admin.example.com.
  • The requested themes folder resides on the main website domain: https://example.com.

So, in the user/themes/example/ folder you need to create and add a .htaccess file with the following code:

# Allow access to these theme files from https://admin.example.com
<IfModule mod_headers.c>
  Header set Access-Control-Allow-Origin "https://admin.example.com"
</IfModule>

It’s important to note that you don’t necessarily need to specify https://example.com, as browsers will always allow and enable access to resources from the same origin they live on.

Fix loading issues with the Front-end Ajax Endpoint

If you’ve configured a template as an Ajax endpoint, it’s considered a public resource by default and allows access from all origins (represented by the wildcard “*”). This means any website can access and interact with the endpoint.

Two options exist for managing CORS access:

  • Server configuration: Similar to the previously used “.htaccess” method, server-side configuration tools modify headers to control access.

  • ExpressionEngine template: A dedicated plugin like “Cross-Origin-Headers” can be installed to directly manage CORS headers within the relevant template.

Both methods assume the endpoint URL is https://example.com/ajax/endpoint.

In the web root’s .htaccess, add:

# Allow cross-domain access to our Ajax endpoint
<IfModule mod_headers.c>
  SetEnvIf Request_URI "/ajax/endpoint" CORS=True
  Header set Access-Control-Allow-Origin "*" env=CORS
</IfModule>

The first line defines an environment variable called CORS, but only for our specified URI. This variable acts as a switch to control CORS behavior. The second line defines the Access-Control-Allow-Origin header as usual but with the env=CORS condition. This ensures the header is only set when the CORS environment variable is explicitly set.

This approach works effectively regardless of whether ExpressionEngine manages the resource and allows the use of regular expressions in URL patterns, similar to how RewriteCond %{REQUEST_URI} is used with mod_rewrite.

Using CORS and CDN Caching

Integrating Cross-Origin Resource Sharing (CORS) with your CDN can be accomplished in two straightforward ways:

  • Configure your origin server’s HTTP headers

This involves adding the Access-Control-Allow-Origin header to your server’s response. The value of this header specifies the allowed origin(s) that can access the resource. For example, you can add the HTTP header Access-Control-Allow-Origin for CSS and font caching.

To use CORS for CDN caching in Apache, this sample code can be added to the configuration file:

<IfModule mod_headers.c>
    <FilesMatch "\.(ttf|ttc|otf|eot|woff|font.css|css)$">
        Header set Access-Control-Allow-Origin "*"
    </FilesMatch>
</IfModule>

To activate CORS in Nginx for CDN caching, the following code can be added in its configuration file:

location ~ \.(ttf|ttc|otf|eot|woff|font.css|css)$ {
    add_header Access-Control-Allow-Origin "*";
}

  • Utilize your CDN provider’s CORS functionality

Many CDNs offer built-in CORS support. By enabling this feature, your CDN will automatically handle the necessary header configuration, saving you time and effort.

RECOMMENDED READING: How to use Cloudflare on Namecheap Domain Pointed to Contabo

Whitelist domains to access resources using CORS

You can implement Server-side configuration, which involves modifying your server’s configuration files to add the Access-Control-Allow-Origin header to responses for your resources. The specific steps will vary depending on your server software (e.g., Apache, Nginx, Node.js, etc.). Check out the following guides:

What are the benefits of using Cross-Origin Resource Sharing?

CORS provides several benefits, including:

Improved security

Before CORS, browsers enforced the Same-Origin Policy, which restricted web pages from making requests to a different domain than the one that served the web page. While this policy is a fundamental security measure, it can be too restrictive for modern web applications that often need to access resources from multiple domains. CORS relaxes these restrictions by allowing controlled cross-origin requests.

CORS allows servers to specify which domains are permitted to access their resources. This is done through the use of HTTP headers, such as the Access-Control-Allow-Origin header, which indicates the origins (domains) that are allowed to access the resource. This ensures that only trusted domains can make cross-origin requests.

CORS introduces a set of HTTP headers that servers can use to specify the permissions for cross-origin requests. These headers include:

  • Access-Control-Allow-Origin: Specifies the origin(s) that are allowed to access the resource. It can be a specific origin, a comma-separated list of origins, or a wildcard (*) indicating that any origin is allowed.

  • Access-Control-Allow-Methods: Specifies the HTTP methods (e.g., GET, POST) that are allowed when accessing the resource.

  • Access-Control-Allow-Headers: Specifies the HTTP headers that are allowed when making the actual request.

By default, cross-origin requests do not include credentials (such as cookies or HTTP authentication) for security reasons. However, if a server allows credentials, the Access-Control-Allow-Credentials header is used to indicate this. It helps prevent unauthorized access to sensitive information.

For certain types of requests (such as those with custom headers or using certain methods), browsers may send a preflight request (an HTTP OPTIONS request) to the server to check whether the actual request is safe to send. The server responds with appropriate CORS headers to indicate whether the actual request can proceed.

RECOMMENDED READING: How to Secure HLS & DASH Streams in Ant Media Server?

Enhanced functionality: 

CORS allows web pages to make requests to a different domain, enabling web applications to access data from APIs hosted on different servers. This is essential for building rich, client-side web applications that can interact with various data sources and services.

CORS enables web pages to integrate with third-party services, such as social media APIs, payment gateways, or other external resources. This is crucial for creating feature-rich applications that can leverage diverse functionalities.

CORS facilitates communication between different origins, allowing web pages from one domain to send asynchronous HTTP requests (e.g., XMLHttpRequest or Fetch API) to another domain. This is particularly useful for scenarios where data needs to be fetched or exchanged between different parts of a web application.

In a microservices architecture, various services may be hosted on different servers with distinct domains. CORS enables seamless communication between these services from the client side, enabling a more modular and scalable approach to building web applications.

CORS enables web pages to fetch resources, such as images, fonts, or stylesheets, from different domains. This allows for improved performance and better user experience by leveraging content delivery networks (CDNs) and other distributed systems.

Single Page Applications (SPAs) often need to load content dynamically without refreshing the entire page. CORS facilitates such dynamic loading of content from different sources, contributing to a smoother and more interactive user experience.

What are the challenges of using Cross-origin Resource Sharing (CORS)?

CORS can also present some challenges, including:

  • increased complexity: CORS can add complexity to web applications, as developers need to be aware of the CORS rules and how to implement them.
  • Potential performance issues: CORS can lead to performance issues, as browsers need to make additional requests to check the Origin header.
  • Limited control for developers: Developers have limited control over how CORS is implemented on their servers.

More related articles to explore

Hire us to handle what you want

Hire us through our Fiverr Profile and leave all the complicated & technical stuff to us. Here are some of the things we can do for you:

  • Website migration, troubleshooting, and maintenance.
  • Server & application deployment, scaling, troubleshooting, and maintenance
  • Deployment of Kubernetes, Docker, Cloudron, Ant Media, Apache, Nginx,  OpenVPN, cPanel, WHMCS, WordPress, and more
  • Everything you need on AWS, IBM Cloud, GCP, Azure, Oracle Cloud, Alibaba Cloud, Linode, Contabo, DigitalOcean, Ionos, Vultr, GoDaddy, HostGator, Namecheap, DreamHost, and more.
 

We will design, configure, deploy, or troubleshoot anything you want. Starting from $10, we will get your job done in the shortest time possible. Your payment is safe with Fiverr as we will only be paid once your project is completed.