We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

CORS in Express

Express provides the cors package to set CORS headers. You should only place the middleware it provides on routes that are intentionally available to other browser origins.

Imagine an app that applies this custom middleware to every API route:

export const apiCors: RequestHandler = (req, res, next) => {
  const origin = req.header("Origin");

  if (origin) {
    res.setHeader("Access-Control-Allow-Origin", origin);
    res.setHeader("Access-Control-Allow-Credentials", "true");
  }

  next();
};

Reflecting an arbitrary origin while allowing credentials gives every requesting website permission to read authenticated API responses. Scary!

Public and Private APIs

Not every API route needs the same policy. A storefront might have two categories:

  • The product catalog is public and can be read cross-origin without credentials.
  • Account and order APIs contain authenticated data and don't need cross-origin access.

The public route can use narrowly scoped middleware:

import cors from "cors";

app.use(
  "/api/products",
  cors({
    origin: "*",
    credentials: false,
    methods: ["GET"],
    allowedHeaders: [],
  }),
);

Using * is fine here because the response is public and doesn't allow (or need any) credentials. The authenticated routes shouldn't get CORS middleware at all. Same-origin browser requests and non-browser clients don't need CORS permission headers.

The cors package also handles relevant preflight OPTIONS requests automatically, so you don't need to add a separate route in your application logic for them.

Assignment

Bearly Secure grants every requesting origin access to authenticated APIs. Replace its global policy with route-scoped CORS.

  1. npm run attacker-lab
    

If you're on Firefox, the test may still pass. You'll need to switch to Chrome to verify the tests manually.

With Bearly Secure and Bearly Evil still running, run and submit the CLI tests from the project root.