# What is CORS?

Source: https://tpiros.dev/blog/what-is-cors

Picture this: you've built an application and now you want to consume a REST API. You test with `curl` or [Postman](https://www.getpostman.com) and everything works. Open the browser and nothing. The developer console spits out `Failed to load resource: Origin * is not allowed by Access-Control-Allow-Origin.` Sound familiar?

Let's look at what CORS is, when it bites, and what you can do about it.

## CORS

CORS stands for 'Cross-Origin Resources Sharing'. As the name suggests, it governs how resources get shared across different origins.

A simple cross-origin request happens when domain1.com tries to access a resource from domain2.com (an image, a CSS file, anything). This carries security implications, so browsers block cross-origin HTTP requests by default.

## When do CORS exceptions happen?

The browser blocks cross-origin resource sharing when you request something from a different domain, protocol, or port than the one you're making the request from.

This means even local development can trip you up. If your custom REST API runs on `http://localhost:3000/api`, an Angular application on `http://localhost:4200` won't be able to consume it. Different ports are enough to trigger the block.

> For the technically curious, I'd recommend the actual [CORS Protocol standard document](http://) for the full specification. We're covering the essentials here.

## Preflight request

Browsers automatically fire a 'preflight' request as part of a CORS request to check whether the server understands the CORS protocol. It uses the HTTP `OPTIONS` method. This preflight determines whether the actual request is safe to send.

## How to avoid CORS?

That question is a bit misleading (I'll admit). There's no way to avoid CORS. It's baked into the browser's security.

> Some browsers let you disable web security entirely. Chrome accepts a `--disable-web-security` flag, for instance. I'd **strongly recommend against this**. It kills all web security features, not just CORS. Treat this as something you should never do.

### Think server-side code

To get past CORS restrictions, you need to work on the server side. The browser sends a request to a service. If that service isn't set up to handle CORS requests, the browser can't do anything except throw the `Origin * is not allowed by Access-Control-Allow-Origin` error back at you.

Back to our example: a REST API on `http://localhost:3000` and an Angular application on `http://localhost:4200` trying to consume it.

Depending on how you've built the API, there's almost certainly a package or library that handles CORS for you.

I tend to use [Restify](https://www.npmjs.com/package/restify) for building REST APIs with Node.js. Restify has a package called [Restify-CORS-Middleware](https://www.npmjs.com/package/restify-cors-middleware) that does exactly what its name says.

Here's what it looks like in code:

```javascript
const restify = require('restify');
const corsMiddleware = require('restify-cors-middleware');

const cors = corsMiddleware({
  origins: ['http://localhost:4200'], // an array of origins
});

const server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);

server.get('/api/products', (request, response) => {
  response.json({ message: 'hello REST API' });
});

server.listen(3000, () => console.info(`Magic happens on port 3000`));
```

The `cors` variable calls the middleware and accepts an array of origins. Every URL in that array can consume the API without triggering a CORS error.

> You could put `http://localhost:*` or even `*` in the origins array. I'd strongly advise against this, especially in production.

### Server-side code is not accessible

The above works when you control the API. But what about a closed system where you can't touch the source code?

Example: you want to pull documents from a NoSQL database via a REST API call. [MarkLogic](http://www.marklogic.com), an Enterprise NoSQL database, exposes a [/v1/documents](https://docs.marklogic.com/REST/GET/v1/documents) endpoint for exactly this.

Try to hit it from the browser and you'll get the CORS error. You can't rewrite the database's source code just to let your localhost app through.

#### Proxies

The solution: proxy the requests. Node.js plus the [request](https://www.npmjs.com/package/request) and [http-proxy](https://www.npmjs.com/package/http-proxy) packages make this quick.

The concept is simple. Create a server, create a proxy server, redirect requests. Here's the implementation:

```javascript
// app.js
const request = require('request');
const express = require('express');
const app = express();
const router = express.Router();

router.route('/*').get(function (req, res) {
  const url = req.url;
  const marklogicRESTAPI = 'http://localhost:8000';
  request(
    `${marklogicRESTAPI}${url}`,
    {
      auth: {
        user: 'admin',
        pass: 'admin',
        sendImmediately: false,
      },
    },
    (error, response, body) => res.end(body)
  );
});

app.use('/', router);
app.listen(3000);

// proxy.js
const httpProxy = require('http-proxy');

const proxy = httpProxy
  .createServer({
    target: 'http://localhost:3000',
  })
  .listen(5555);

proxy.on('proxyRes', function (proxyReq, req, res, options) {
  // add the CORS header to the response
  res.setHeader('Access-Control-Allow-Origin', '*'); // never use '*' in production!
});
```

Here's what's happening. `app.js` creates a simple Express web server on port 3000. Its route catches all GET requests (`router.route('/*').get...`) and forwards them to `http://localhost:8000` (MarkLogic's REST API). So `http://localhost:3000/v1/documents?uri=/test.json` becomes `http://localhost:8000/v1/documents?uri=/test.json`.

`proxy.js` spins up another HTTP server on port 5555. Any request hitting `http://localhost:5555` gets forwarded to `http://localhost:3000`, with an `Access-Control-Allow-Origin` header tacked on.

Here's how the Angular side consumes it:

```javascript
constructor(private http: Http) {
  this.http.get('http://localhost:5555/v1/documents?uri=/test.json')
  .map(response => response.json())
  .subscribe(response => console.log(response));
}
```

The flow: Angular hits `http://localhost:5555/v1/documents?uri=/test.json`. The proxy forwards it to `http://localhost:3000/v1/documents?uri=/test.json` with the CORS header attached. That request then gets translated to `http://localhost:8000/v1/documents?uri=/test.json`, which pulls the document from the database.

Without these proxies, a direct call to `http://localhost:8000/v1/documents?uri=/test.json` from the browser would trigger a CORS error. With them in place, the data flows through cleanly.
