Cross Domain JSON Requests
Published: 2021-03-29 17:10:34

---
title: Cross Domain JSON Requests
published: true
description: Correctly configuring CORS for content-type application/json
tags: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9s7q3se8i2f8w2uao2qb.png
---

The use of dynamic requests to backend servers is prevalent in modern web applications. Despite its commonplace nature, there are some *gotchas* that trip up even experienced developers.

### TL;DR

> In order to successfully preflight a JSON-encoded request to a different domain, the *browser's* fetch request must include the HTTP header `access-control-request-headers: content-type`.
>
> In order to signal that a JSON-encoded request from a different domain is permitted, the *remote server* must be correctly configured to respond with the HTTP header `access-control-allow-headers: content-type`.

---

### Basic CORS rules

Before getting started, let's review when Cross Origin Resource Sharing (CORS) is required.

   * CORS is only used when a web page needs to access something that is hosted on a       different domain.
   * CORS is never used for HTTP requests made with the methods: `GET`, `HEAD` or `OPTIONS`
   * CORS is a browser-to-server protocol. It *uses* HTTP for communication, but HTTP *per se* knows nothing about CORS. Because of this, requests sent via `cURL`, or tools
      like `Postman`, do not involve CORS, and will succeed, while the same request made by the browser will fail.
   * CORS does not enhance website security, rather it weakens security. Implementing it carefully is important.

---

### Simple CORS requests

There are two types of CORS requests: simple and preflight.

Consider a scenario where a web page hosted on `www.example.com` submits a `<form>` to a backend server at `api.example.com`. This is an example of a simple CORS request. It follows this path:

   1. The browser determines that the remote resource is not on the same domain as the web page, so it adds an extra header to the `POST` request: `origin: www.example.com`.
   2. The remote server recognizes that this is a request coming from a different host, and checks its rule book to determine how to respond.
   3. If the specified origin is not in the remote server's configuration, the server responds with status code `403` and an empty payload.
   4. On the other hand, if the remote server is configured to honor requests from the specified origin, it handles the request, returning an appropriate status code such as `200`.

In this example, the type of payload is significant. POST requests having content type `application/x-www-form-urlencoded` are made using the simple CORS protocol. This is the HTML `<form>` submission standard. Here's what the software developer codes:

```javascript
fetch('https://api.example.com/order_handler', {
    method: 'POST',
    mode: 'cors',
    body: wwwFormData
});
```

One further note before moving on, the use of the CORS protocol is only triggered by the browser when *dynamic* requests are made by JavaScript. In the above example, if the `wwwFormData` had been submitted directly by a SUBMIT button, CORS would not be invoked. The HTML for this type of submission is simply:

```html
<form action='https://api.example.com/order_handler' method='POST'>
```

---

### Preflight CORS

The second type of CORS request involves a <span>preflight</span> request made using the HTTP `OPTIONS` method.

Consider the same scenario as above, but this time the developer chooses to format the data as JSON. The communication exchange follows this path:

   1. The payload is specified by the developer to be `content-type: application/json`.
   2. The browser does not recognize this content type as one of the CORS "safelisted types", so it sends an `OPTIONS` request to the remote server with two headers `origin: www.example.com`
and `access-control-request-headers: content-type`.
   3. As before, the remote server checks its configuration rule book to determine whether or not to honor requests from that origin, and further checks to see if it is ready to handle non-standard content types.
   4. If both of those conditions are satisfied, the server responds to the OPTIONS request with two headers: `access-control-allow-origin: www.example.com` and `access-control-allow-headers: content-type`.
   5. The browser sees that the remote server intends to honor the request, so it issues a POST request with the JSON payload and the `origin: www.example.com` and `access-control-request-headers: content-type` headers.
   6. The remote server honors the POST and responds with an appropriate status code.

The software developer codes it like this:

```javascript
fetch('https://api.example.com/order_handler', {
    method: 'POST',
    mode: 'cors',
    headers: {'content-type': 'application/json'},
    body: jsonData
});
```

---

### Configuring the remote server

Every web server has a way to enable CORS, and a way to allow `content-type` headers. Here are links to the docs for a few of them:

   * For Apache Web Server, add this to the remote server's configuration: `Header always set Access-Control-Allow-Headers "content-type"`
   * For Nginx Web Server, add this to the remote server's configuration:  `add_header Access-Control-Allow-Headers "content-type"`
   * <a href='https://blogs.iis.net/iisteam/getting-started-with-the-iis-cors-module'>IIS Server</a> CORS configuration
   * <a href='https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html'>Amazon EC2</a> CORS configuration
   * <a href='https://rwserve.readwritetools.com/cross-origin.blue'>Read Write Serve HTTP/2 Server</a> CORS configuration

---

Originally published at [Cross Domain JSON Requests](https://medium.com/javascript-fanboi/2021-043-cross-domain-json-requests-3c47b382c869). Read more [JavaScript Fanboi](https://medium.com/javascript-fanboi) articles here.