You need to enable JavaScript to run this app.

How to Create an HTTP Proxy in Next.js

Summary:

This blog demonstrates how to create an HTTP proxy in Next.js using serverless functions. HTTP proxies can be used to add an extra client-server transport layer, providing several benefits, including securing authorization tokens as http-only cookies, filtering requests, and enhancing protection and security. The blog provides a simple step-by-step guide on setting up an HTTP proxy by creating a catch-all route in the 'api' directory of next.js and utilizing the 'http-proxy' package. The proxy adds a middleware layer to all API calls, separates auth routes for handling cookies, and includes existing auth tokens in the headers of other APIs.

Category
Next.js
Time to read
10 min.
Published at
2021-06
How to Create an HTTP Proxy in Next.js

1. Introduction

With next.js introducing API routes and serverless functions, a lot of ideas become possible for front-end developers.

Some of the benefits are

  • No need to handle CORS policy because we are making API requests from one server to another server.
  • Conntecting directly to databases.
  • Creating RESTful APIs without needing any backend server.
  • Implementing middlewares and proxies
  • ...

You can read more about this concepts in next.js documentation.

A way of using them is by writing HTTP proxies to add proxies as an extra client-server transport layer.

2. Why?

There are so many interesting things that come with using proxies, for example, you can save an authorization token as an http-only cookie and pass every API through the HTTP proxy to add the token to the header. This way accessing tokens is a lot harder for malicious users (not impossible of course). Other useful things you can do are: "hiding the IP address", "filtering requests", "protection and security", "caching" and ...

3. How?

So how to create an HTTP proxy with next.js serverless functions? It's so simple, First you need two packages, cookies and http-proxy.

We need to a catch all route in the api directory. for that create a pages/api/proxy/[...path].js and paste this code into it.

import * as HttpProxy from "http-proxy";
import url from "url";
import Intervals from "@constants/Intervals";
import { TOKEN_COOKIE_KEY } from "@constants/cookies";
import {
  externalApiBaseURL,
  headerTokenKey,
  proxyBasePath,
  proxyBasePathRegExp,
} from "@config";
import * as Cookies from "cookies";

const proxy = HttpProxy.createProxyServer();

const config = {
  api: {
    bodyParser: false,
  },
};

export default (req, res) => {
  return new Promise((resolve, reject) => {
    const pathname = url.parse(req.url).pathname;
    const isAuth = pathname === proxyBasePath + "/auth/login";
    const cookies = new Cookies(req, res);
    const token = cookies.get(TOKEN_COOKIE_KEY);

    req.url = req.url.replace(proxyBasePathRegExp, "");
    req.headers.cookie = "";

    if (token) req.headers[headerTokenKey] = token;

    if (isAuth) proxy.once("proxyRes", interceptLoginResponse);

    proxy.once("error", reject);
    proxy.web(req, res, {
      target: externalApiBaseURL,
      autoRewrite: false,
      selfHandleResponse: isAuth,
    });

    function interceptLoginResponse(proxyRes, req, res) {
      let apiResponseBody = "";
      proxyRes.on("data", (chunk) => {
        apiResponseBody += chunk;
      });
      proxyRes.on("end", () => {
        try {
          const response = JSON.parse(apiResponseBody);
          const token = response?.result?.token;
          const cookies = new Cookies(req, res);

          cookies.set(TOKEN_COOKIE_KEY, token, {
            maxAge: Intervals.Month * 1000,
            httpOnly: true,
            sameSite: "lax",
          });

          delete response?.result?.token;

          res.status(200).json(response);
          resolve(response);
        } catch (err) {
          reject(err);
        }
      });
    }
  });
};

The code speaks for itself, but in a simple word, what we are doing here is

  • Adding a thin layer or middleware to all of our API calls
  • Crating a serverless function to represent the proxy
  • Separating auth routes that are responsible for setting cookies from other APIs
    • If the passing API was an auth related:
      • Adding response token to cookie with needed attributes
      • Removing token from response to prevent javascript accessing
    • Or else, adding existing auth token to the header of other APIs
Favourite Books
BooksPoems
Favourite Songs
PlaylistsArtists
Favourite Shows
AnimationsSeriesAnime