cors express preflight: working versions (tested 2026-10-16)
Configure cors with express to reflect allowed origins, answer OPTIONS preflight with Access-Control-Allow-* headers, and deny a disallowed origin, tested offline with supertest.
passed3 passed · 0 failed2026-10-16 15:20 UTC- Status
- passed
- Last passed
- 2026-10-16 15:20 UTC
- Tests
- 3 / 3
- Language
- TypeScript
- Runtime
- node v22.23.3
npm install --no-audit --no-fund --ignore-scripts=false npm test
node v22.23.3 linux 6.17.0-1022-azure x64 runner: github-actions 38923127324
The code
Exactly the files that passed. Your agent can pull them with get_recipe("cors-express-preflight") (install), or see them on GitHub.
{
"name": "cors-express-preflight",
"private": true,
"type": "module",
"scripts": {
"test": "node --import tsx --test test/*.test.ts"
},
"dependencies": {
"cors": "2.8.6",
"express": "5.3.0"
},
"devDependencies": {
"supertest": "7.3.1",
"@types/cors": "2.8.19",
"@types/express": "5.0.6",
"@types/supertest": "7.2.1",
"@types/node": "26.6.5",
"tsx": "4.23.15"
}
}
import express, { type Express } from "express";
import cors, { type CorsOptions } from "cors";
export const defaultAllowedOrigins = [
"https://app.example.com",
"https://admin.example.com",
];
export function createApp(allowedOrigins: string[] = defaultAllowedOrigins): Express {
const app = express();
const corsOptions: CorsOptions = {
origin(origin, callback) {
if (!origin) {
callback(null, true);
return;
}
callback(null, allowedOrigins.includes(origin));
},
credentials: true,
methods: ["GET", "POST", "OPTIONS"],
allowedHeaders: ["Content-Type", "Authorization"],
optionsSuccessStatus: 204,
};
app.use(cors(corsOptions));
app.use(express.json());
app.get("/health", (_req, res) => {
res.json({ ok: true });
});
app.post("/echo", (req, res) => {
res.json({ received: req.body ?? null });
});
return app;
}
import { test } from "node:test";
import assert from "node:assert/strict";
import request from "supertest";
import { createApp } from "../src/app.ts";
test("reflects an allowed origin on a simple request", async () => {
const app = createApp();
const res = await request(app)
.get("/health")
.set("Origin", "https://app.example.com");
assert.equal(res.status, 200);
assert.equal(res.headers["access-control-allow-origin"], "https://app.example.com");
assert.equal(res.headers["access-control-allow-credentials"], "true");
assert.deepEqual(res.body, { ok: true });
});
test("answers OPTIONS preflight with Access-Control-Allow-* headers", async () => {
const app = createApp();
const res = await request(app)
.options("/echo")
.set("Origin", "https://admin.example.com")
.set("Access-Control-Request-Method", "POST")
.set("Access-Control-Request-Headers", "content-type");
assert.equal(res.status, 204);
assert.equal(res.headers["access-control-allow-origin"], "https://admin.example.com");
assert.equal(res.headers["access-control-allow-credentials"], "true");
assert.match(res.headers["access-control-allow-methods"], /POST/);
assert.match(res.headers["access-control-allow-headers"], /content-type/i);
});
test("denies a disallowed origin by omitting the allow-origin header", async () => {
const app = createApp();
const res = await request(app)
.get("/health")
.set("Origin", "https://evil.example.com");
assert.equal(res.headers["access-control-allow-origin"], undefined);
assert.equal(res.headers["access-control-allow-credentials"], undefined);
});
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.
Related stacks
express-validator request checks with supertest
Validate Express JSON bodies and query params with express-validator, returning field errors, tested with supertest offline.
Joi request validation middleware for Express 5
Validate Express 5 bodies and query strings with Joi schemas in a reusable middleware, with defaults, type conversion, stripUnknown and 400 error details, tested with supertest.
Twilio webhook signature validation in Express with TwiML replies
Validate X-Twilio-Signature on inbound SMS webhooks in Express with twilio.validateRequest, including query strings and tampered params, and reply with MessagingResponse TwiML, tested offline with supertest.
Express 5 + express-session login flow, e2e-style over real HTTP with a cookie jar
Session login/logout with express-session (regenerate on login, httpOnly cookies), tested end to end against a real listening server using fetch-cookie, no browser or Playwright.