Skip to main content

api-cors-express

@rtorcato/api-cors-express wraps the cors package with stricter defaults and a friendlier API. The main difference: a bare string origin is treated as a list (proper per-request matching) rather than a static header, which avoids leaking the Access-Control-Allow-Origin value on mismatched origins.

Install

pnpm add @rtorcato/api-cors-express express

express is a peer dependency (^4.18 || ^5).

Basic usage

import express from 'express'
import { corsMiddleware } from '@rtorcato/api-cors-express'

const app = express()

app.use(corsMiddleware({ origin: 'https://app.example.com' }))

Register it before your routes so it applies everywhere.

Options

corsMiddleware({
/** Required. Allowed origins — string, array, regexp, or predicate. */
origin: 'https://app.example.com',

/** Include credentials (cookies, auth headers). Default: true */
credentials: true,

/** Allowed methods. Default: GET POST PUT PATCH DELETE OPTIONS */
methods: ['GET', 'POST'],

/** Allowed request headers. Default: Content-Type, Authorization */
allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-Id'],

/** Preflight cache duration in seconds. Default: 600 */
maxAge: 3600,
})

Multiple origins

app.use(corsMiddleware({
origin: ['https://app.example.com', 'https://admin.example.com'],
}))

Dynamic origin (predicate)

const ALLOWED = new Set(['https://app.example.com', 'https://staging.example.com'])

app.use(corsMiddleware({
origin: (incoming) => ALLOWED.has(incoming ?? ''),
}))

Return true to allow the origin, false to block it.

Development: allow all

app.use(corsMiddleware({
origin: process.env.NODE_ENV === 'production'
? 'https://app.example.com'
: '*',
}))
warning

origin: '*' with credentials: true is rejected by browsers. If you need cookies or Authorization headers in development, use the exact origin instead of a wildcard.