Practical examples of CORS with Node.js and Koa framework
Simple example of CORS in a minimal Koa API
Let’s start with the smallest working example of CORS with Node.js and Koa framework. This is the baseline you can compare all other patterns against.
npm install koa @koa/cors
// server.js
const Koa = require('koa');
const cors = require('@koa/cors');
const app = new Koa();
// Simple, wide‑open CORS – fine for local development only
app.use(cors());
app.use(async ctx => {
ctx.body = { message: 'Hello from Koa with CORS' };
});
app.listen(4000, () => {
console.log('API listening on http://localhost:4000');
});
This example of CORS configuration:
- Allows all origins (
Access-Control-Allow-Origin: *) - Supports simple GET/HEAD/POST requests
- Works perfectly for local React/Vue/Angular frontends hitting
http://localhost:4000
It’s one of the best examples for onboarding junior developers, because it gets them unblocked quickly while you explain why production needs stricter rules.
Real examples of CORS with Node.js and Koa framework for single‑page apps
Most modern use cases for CORS are single‑page apps (SPAs) hosted on a different origin than the API. Think:
- Frontend:
https://app.example.com - API:
https://api.example.com
Here’s a more realistic example of CORS with Node.js and Koa framework tuned for that setup:
const Koa = require('koa');
const cors = require('@koa/cors');
const app = new Koa();
const allowedOrigins = [
'https://app.example.com',
'https://admin.example.com'
];
app.use(cors({
origin: (ctx) => {
const requestOrigin = ctx.request.header.origin;
if (allowedOrigins.includes(requestOrigin)) {
return requestOrigin; // echo back the allowed origin
}
return ''; // no CORS headers for disallowed origins
},
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization'],
maxAge: 86400 // one day in seconds
}));
app.use(async ctx => {
ctx.body = { status: 'ok' };
});
app.listen(4000);
Why this pattern works well in 2024–2025:
- Frontend frameworks increasingly rely on custom headers and non‑GET methods, so
allowMethodsandallowHeadersneed to be explicit. - Using a function for
originlets you dynamically approve or reject requests based on environment, tenant, or even feature flags. maxAgereduces preflight OPTIONS traffic, which matters more as APIs scale.
This is one of the best examples of balancing usability and security for production SPAs without over‑complicating the code.
Examples of CORS with Node.js and Koa framework using credentials (cookies, sessions)
If you’re using cookies or HTTP‑only session tokens from the browser, CORS rules get stricter. Browsers require:
Access-Control-Allow-Credentials: true- A specific origin (no
*) withCredentials: trueon the frontend request
Here’s a clear example of CORS with Node.js and Koa framework using credentials safely:
const Koa = require('koa');
const cors = require('@koa/cors');
const session = require('koa-session');
const app = new Koa();
app.keys = ['super-secret-key'];
app.use(session(app));
app.use(cors({
origin: 'https://app.example.com',
credentials: true, // allow cookies
allowMethods: ['GET', 'POST'],
allowHeaders: ['Content-Type']
}));
app.use(async ctx => {
ctx.session.views = (ctx.session.views || 0) + 1;
ctx.body = { views: ctx.session.views };
});
app.listen(4000);
On the frontend (for example, a React app):
fetch('https://api.example.com/profile', {
credentials: 'include'
});
This is a real example you’ll see in many production dashboards: the Koa API sets secure cookies, and the React or Vue app reads authenticated data via CORS. The important point is that you never pair credentials: true with origin: '*' in the Koa config; browsers will reject that, and even if they didn’t, it would be a security risk.
For deeper background on why cookies and cross‑site requests are sensitive, the W3C CORS specification and MDN documentation are worth a read:
- https://www.w3.org/TR/cors/
- https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Best examples of dynamic CORS for multi‑tenant or staging environments
Teams in 2024–2025 rarely have just one frontend origin. You might have:
https://app.example.com(production)https://staging.example.com(staging)http://localhost:5173(local Vite dev server)
Here’s one of the best examples of CORS with Node.js and Koa framework that adapts across those environments without editing code every time you deploy:
const Koa = require('koa');
const cors = require('@koa/cors');
const app = new Koa();
// Load from env or config service in real projects
const allowedOrigins = (process.env.CORS_ORIGINS || '')
.split(',')
.map(o => o.trim())
.filter(Boolean);
app.use(cors({
origin: (ctx) => {
const origin = ctx.request.header.origin;
if (allowedOrigins.includes(origin)) return origin;
return ''; // no CORS headers
},
allowMethods: ['GET', 'POST', 'PATCH', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization', 'X-Request-Id'],
exposeHeaders: ['X-Request-Id'],
maxAge: 600
}));
// Example route that sets X-Request-Id header
app.use(async ctx => {
ctx.set('X-Request-Id', crypto.randomUUID());
ctx.body = { ok: true };
});
app.listen(4000);
This pattern is common in larger organizations: DevOps controls allowed origins via environment variables, while the Koa app simply enforces the list. It also shows how to use exposeHeaders so the frontend can read headers like X-Request-Id for tracing.
Examples include preflight handling and performance tuning
CORS preflight requests (OPTIONS) can quietly add load if your frontend makes lots of non‑simple requests. Modern SPAs often send JSON with Content-Type: application/json and custom headers, which triggers preflight.
Here’s an example of CORS with Node.js and Koa framework that explicitly handles preflight and keeps logs clean:
const Koa = require('koa');
const cors = require('@koa/cors');
const app = new Koa();
app.use(cors({
origin: 'https://app.example.com',
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
allowHeaders: ['Content-Type', 'Authorization'],
maxAge: 3600
}));
// Short‑circuit OPTIONS requests so they don't hit business logic
app.use(async (ctx, next) => {
if (ctx.method === 'OPTIONS') {
ctx.status = 204;
return;
}
await next();
});
app.use(async ctx => {
ctx.body = { data: 'real response' };
});
app.listen(4000);
This is a good example of:
- Letting
@koa/corsset the right headers - Returning a fast 204 for OPTIONS
- Keeping application logs focused on actual business requests rather than browser housekeeping
As API traffic grows, these small performance wins matter. They also make debugging easier because your logs are less noisy.
Real examples of tightening CORS for public vs internal APIs
Not all APIs should be treated the same. In many organizations, you’ll see two patterns side by side.
Public, read‑only API example
Public APIs that just serve read‑only data (for example, public product catalogs or documentation search) often use a more open CORS configuration:
app.use(cors({
origin: '*',
allowMethods: ['GET'],
}));
This example of CORS is acceptable when:
- Data is public anyway
- No credentials are involved
- You want third‑party sites to embed or proxy your data
Internal, sensitive API example
For internal admin tools or APIs that expose PII or financial data, you want something much tighter. Here’s a more locked‑down example of CORS with Node.js and Koa framework:
const allowedOrigins = [
'https://admin.example.com',
'https://security-console.example.com'
];
app.use(cors({
origin: (ctx) => {
const origin = ctx.request.header.origin;
if (allowedOrigins.includes(origin)) return origin;
return '';
},
credentials: true,
allowMethods: ['GET', 'POST'],
allowHeaders: ['Content-Type', 'Authorization'],
}));
This is a pattern security teams like: only trusted admin domains can make browser calls, and requests require credentials. Combined with proper authentication and authorization, this gives you a clear boundary between public and internal surfaces.
For general guidance on secure web application practices, the OWASP Foundation provides well‑maintained resources:
- https://owasp.org/www-project-top-ten/
Example of CORS error handling and developer‑friendly logging
Nothing frustrates front‑end developers more than silent CORS failures. Browsers hide the response from JavaScript when CORS fails, so good server‑side logging is your friend.
Here’s an example of CORS with Node.js and Koa framework that logs rejected origins for easier debugging:
const Koa = require('koa');
const cors = require('@koa/cors');
const app = new Koa();
const allowedOrigins = ['https://app.example.com'];
app.use(cors({
origin: (ctx) => {
const origin = ctx.request.header.origin;
if (!origin) return '';
if (allowedOrigins.includes(origin)) {
return origin;
}
console.warn(`Blocked CORS request from origin: ${origin}`);
return '';
}
}));
app.use(async ctx => {
ctx.body = { ok: true };
});
app.listen(4000);
This is one of those quiet but valuable examples of CORS with Node.js and Koa framework. When someone on the team wires up a new frontend origin and forgets to update the config, the logs immediately tell you what went wrong.
2024–2025 trends that affect CORS in Koa apps
A few trends are shaping how teams think about CORS in Node.js and Koa projects right now:
- More cross‑origin frontends: Micro‑frontends, separate marketing and app domains, and multiple admin tools mean more origins to manage.
- Stronger browser privacy features: Modern browsers are tightening cookie rules (SameSite, partitioned cookies), which interact with CORS when you rely on cross‑site cookies.
- API gateways and edge proxies: Many teams terminate CORS at an API gateway (NGINX, API Gateway, Cloudflare Workers) and use Koa for business logic only. Even then, understanding these examples of CORS with Node.js and Koa framework helps you reason about what the gateway should do.
If you’re working in regulated industries (healthcare, finance, education), CORS is one small piece of a broader security picture. While CORS itself isn’t a health or medical topic, organizations like the U.S. National Institute of Standards and Technology (NIST) publish security guidelines that influence how web APIs are designed:
- https://csrc.nist.gov/publications
FAQ: examples of common CORS questions for Koa developers
Q: Can you show an example of allowing multiple subdomains with Koa CORS?
Yes. Instead of listing every subdomain, you can pattern‑match:
app.use(cors({
origin: (ctx) => {
const origin = ctx.request.header.origin || '';
if (origin.endsWith('.example.com')) return origin;
return '';
}
}));
This example of CORS accepts https://app.example.com, https://admin.example.com, and https://anything.example.com, but rejects unrelated domains.
Q: Do I always need @koa/cors, or can I write headers manually?
You can absolutely write headers yourself with Koa’s ctx.set, but @koa/cors handles a lot of boring edge cases correctly. For most teams, the best examples of production code use the middleware and only customize what’s necessary.
Q: What are examples of unsafe CORS configurations in Koa?
A few red flags:
origin: '*'combined withcredentials: true- Allowing all methods and all headers for sensitive internal APIs
- Echoing back any
Originheader without checking it against a list
If you see those patterns in your Koa code, treat them as things to tighten up.
Q: Is CORS a security feature or just a browser annoyance?
It’s both. CORS is enforced by browsers to prevent malicious sites from reading responses from your API using a logged‑in user’s credentials. Server‑side, you still need authentication and authorization; CORS just controls which browser origins can see responses. These examples of CORS with Node.js and Koa framework are about cooperating with that browser security model rather than fighting it.
Q: Where can I learn more beyond these examples of CORS with Node.js and Koa framework?
For deeper HTTP and web security background, MDN and W3C are excellent references. For general security practices, OWASP and NIST provide high‑quality guidance. Combine those with the real examples in this article, and you’ll be in a strong position to configure CORS correctly in your Koa apps.
Related Topics
Examples of CORS in Flask API: 3 Practical Examples That Actually Match Real Apps
Real-world examples of handling CORS errors in front-end applications
Practical examples of CORS with Node.js and Koa framework
The best examples of CORS: practical examples with developer tools
Explore More Implementing CORS in APIs
Discover more examples and insights in this category.
View All Implementing CORS in APIs