How to Solve CORS using a Proxy Server and Koa

Originally published at labs.thisdot.co

Aug 3, 2021 · 5 minutes read · [JavaScript] [TypeScript] [Web Development] [Proxy Server]

No matter how much experience you have in software development, you’ve likely had to deal with the CORS problem.

The good news is that there are now new and different ways to solve this issue, from using an extension for your favorite browser, to defining a custom solution.

In this post, I’ll explain how to implement a basic Proxy Server using Node.js so that you can use it even if you’re using a different programming language for your main application.

The Problem

Let’s suppose you’re building a Single-Page Application, and it’s running fine in your local environment http://localhost:8000. At some point, you’ll need to perform HTTP requests to an existing server to obtain data, or even authenticate you. All these services are running below https://app.mydomain.com.

At the time you make the requests, you may have an error like the one shown below:

Access to fetch at 'https://app.mydomain.com' from origin 'http://localhost:8000' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

In this particular case, the browser will restrict the cross-origin HTTP requests for security reasons.

The Solution

In the problem explained above, there is a Single-Page Application that needs access to resources or data. So, there is a security issue on the frontend side, and it can be solved by running a server in just a few steps.

Koa

For the Proxy Server implementation, we’re going to use Koa, which is a web framework for Node.js.

Koa is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs.

It seems that there are very good reasons to use it, right? :-)

Prerequisites

You’ll need to have installed the following tools in your local environment:

  • Node.js. Preferably the latest LTS version.
  • A package manager. You can use either NPM or Yarn. This tutorial will use NPM.

Koa Installation

Before installing Koa and other dependencies, let’s create a folder for the Proxy Server:

mkdir proxy-server
cd proxy-server

Now, let’s install Koa as the first dependency

npm install koa

As the next step, let’s create a proxy.js file with the following content:

const Koa = require("koa");
const app = new Koa();

app.listen(3000);
console.log("listening on port 3000");

This is the simplest way to create an HTTP server using Koa. You can run it through node proxy.js command. Of course, it is not very useful yet, but it will help as a basis for implementing the proxy.

Koa Proxy and CORS

It’s time to install the next dependencies: @koa/cors and koa-proxies:

npm install @koa/cors koa-proxies
  • @koa/cors is a package to enable CORS (Cross-Origin Resource Sharing) with Koa.
  • koa-proxies is a package powered by http-proxy, which is a full-featured HTTP proxy for Node.js

Now, let’s update the proxy.js file, including @koa/cors, to enable CORS in the current implementation.

const Koa = require("koa");
const cors = require("@koa/cors");
const app = new Koa();
const port = process.env.PORT || 3000;

app.use(cors());

app.listen(port);
console.log(`listening on port ${port}`);

As you can see, the Koa object gets available through new Koa(), and right after that, you can apply a middleware using the app.use() method.

  • cors(), enable CORS with default options, and allow several HTTP Methods.

Take a look the available Koa middleware list for more reference.

Proxy Server

As the last step, let’s configure the Koa proxy using the installed koa-proxies library.

const Koa = require("koa");
const cors = require("@koa/cors");
const proxy = require("koa-proxies");
const app = new Koa();
const port = process.env.PORT || 3000;

app.use(cors());

app.use(
  proxy("/", {
    target: "https://app.mydomain.com",
    changeOrigin: true,
    logs: true,
  })
);

app.listen(port);
console.log(`listening on port ${port}`);

Again, the app.use() method enables the use of proxy() as a middleware. Pay attention to the used options:

  • target, the URL string to be parsed
  • changeOrigin, changes the origin of the host header to the target URL
  • logs, enable default logs

The TypeScript Solution

The previous solution works fine using JavaScript only. In case you require using TypeScript, you’ll need to create the tsconfig.json file first:

tsc --init

This command will auto-generate the tsconfig.json file using default options for the compiler. Let’s apply a couple of updates before moving forward:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "esModuleInterop": true
  }
}

Next, let’s install the TypeScript types for koa and @koa/cors packages:

npm install --save-dev @types/koa @types/koa__cors

Finally, create the proxy.ts file with the following content:

// proxy.ts

import Koa from "koa";
import cors from "@koa/cors";
import proxy from "koa-proxies";

const app: Koa = new Koa();
const port: number | string = process.env.PORT || 3000;

app.use(cors());

const proxyOptions: proxy.IKoaProxiesOptions = {
  target: "https://app.mydomain.com",
  changeOrigin: true,
  logs: true,
};

app.use(proxy("/", proxyOptions));

app.listen(port);
console.log(`listening on port ${port}`);

As you may see in the previous code snippet, it’s about using the right types, and configuring the TypeScript compiler.

You can run the proxy.ts file using this command:

npm run start

Which will run the TypeScript compiler followed by the generated script: tsc && node dist/proxy.js.

Source Code of the Project

Find the complete project in this GitHub repository: cors-proxy-server-koa. Do not forget to give it a star ⭐️, and play around with the code.


Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work.

tweet Share