Client-Server Interaction

Cross-Origin Resource Sharing


Learning Objectives

  • You know of same-origin policy and cross-origin resource sharing.

Same-Origin Policy

Services offered over the web can be accessed practically from anywhere with an internet access. To prevent unauthorized access and use of resources, browsers have a Same-Origin Policy that restricts how a document or a script loaded from one origin can interact with a resource at another origin.

The term origin is defined as the combination of the protocol, domain, and port of a URL. For example, the origin of https://example.com:8080/path is https://example.com:8080.

As an example, requests that attempt to retrieve JSON data from a different origin than the one from where the site has been loaded are, by default, blocked by the browser. When an application attempts to make a request with the fetch method to a different origin (“cross-origin server”), the browser checks whether a header called Access-Control-Allow-Origin is present in the response. If the header is not present, the processing of the response is blocked and an error is thrown from the fetch method.

This process is shown in Figure 1 below, where the browser first retrieves a page from one origin and then attempts to retrieve JSON data from a different origin based on JavaScript code.

Fig 1. — Retrieving a site from a server, where JavaScript code of the site instructs retrieving JSON data from a cross-origin server.

Thrown errors are visible in the browser console. The error message typically reads “Access to fetch at ‘https://cross-origin-server.com/data’ from origin ‘https://origin-server.com’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.” — an example of such an error is shown in Figure 2.

Fig 2. -- Example of an error message in the browser console when a cross-origin request is blocked.

Fig 2. — Example of an error message in the browser console when a cross-origin request is blocked.

Loading Exercise...

Cross-Origin Resource Sharing (CORS)

Deciding on what is allowed and what is not allowed is the key to defining a Cross-Origin Resource Sharing (CORS) policy, which includes defining the allowed origins, methods, and headers. CORS is a mechanism that allows many resources (e.g. fonts, JavaScript, etc.) on a web page to be requested from another domain outside the domain from which the resource originated.

As an example, the header Access-Control-Allow-Origin is used to define the allowed origins. The header can have a value of *, which means that requests from any origin are allowed, or it can have a specific origin, which means that requests from that origin are allowed.

Simple and Preflighted Requests

CORS behavior is typically divided into two types of requests: simple requests and preflighted requests.

Simple requests include e.g. GET requests with no custom headers, POST requests with no custom headers, and POST requests with Content-Type set to application/x-www-form-urlencoded, multipart/form-data, or text/plain. Simple requests are sent directly to the server, after which the response from the server is processed by the browser, and the browser either allows or blocks the response based on the response headers (including Access-Control-Allow-Origin).

Preflighted requests on the other hand, involve first checking whether the server allows the request. This is done by first sending an HTTP OPTIONS request to check whether the server allows the intended request. The server then responds with the headers, which are used to infer whether the intended request would be accepted. If the server allows the request, the browser sends the actual request, and if not, the request is blocked and an error is thrown.

Preflighted requests are used when the request is not a simple request, e.g. when the request method is PUT or DELETE, or when the request has custom headers.

Loading Exercise...

Allowing Cross-Origin Requests in Hono

If we wish to allow cross-origin requests in our applications, the easiest approach is to use an existing middleware. Hono comes with a CORS Middleware, which allows easy configuration of cross-origin requests. The following example outlines how to allow cross-origin requests to a Hono application.

import { Hono } from "jsr:@hono/hono@4.6.5";
import { cors } from "jsr:@hono/hono@4.6.5/cors";

const app = new Hono();
app.use('/*', cors());

let count = 0;

app.get("/count", (c) => c.json({ count }));
app.post("/count", (c) => {
  count++;
  return c.json({ count });
});
app.delete("/count", (c) => {
  count--;
  return c.json({ count });
});

Deno.serve(app.fetch);

Now, when we ask for the options from the server, we see a header access-control-allow-origin that is used to policy cross-origin requests. In this case, requests from browsers accessing sites at any origin are allowed to make requests to the server.

curl -X OPTIONS -v localhost:8000/count
...
< access-control-allow-methods: GET,HEAD,PUT,POST,DELETE,PATCH
< access-control-allow-origin: *
Loading Exercise...