CORS Middleware
cors()
brings fine-grained CORS control to bunway while keeping everything Bun-native. The middleware examines the incoming Origin/Access-Control headers, decides whether to allow the request, and records headers so the router can merge them even when you return a raw Response
object.
Basic usage
import { cors } from "bunway";
app.use(cors()); // wildcard
app.use(cors({ origin: true })); // reflect request origin
app.use(cors({ origin: "https://app.example.com" }));
Set credentials: true
to allow cookies/authorization headers—bunway automatically prevents *
when credentials are enabled by reflecting the incoming origin instead.
app.use(cors({ origin: true, credentials: true }));
Credentials
When credentials: true
, bunway automatically reflects the request origin instead of using *
. Ensure your allow list covers every origin that should receive credentialed responses.
Allow list patterns
string
– match exact originRegExp
– pattern match(origin, ctx) => string | false
– custom logic (return the origin to allow,false
to block)- Arrays combine multiple strings/regexes
app.use(
cors({
origin: (origin) => (origin?.startsWith("http://localhost") ? origin : false),
allowPrivateNetwork: true,
})
);
Preflight requests
Preflight (OPTIONS
) requests are answered automatically with:
Access-Control-Allow-Origin
Access-Control-Allow-Methods
(customizable viamethods
option)Access-Control-Allow-Headers
(explicit list or echo request header)Access-Control-Allow-Credentials
whencredentials: true
Access-Control-Max-Age
(default 600 seconds)Access-Control-Allow-Private-Network
whenallowPrivateNetwork: true
The middleware also ensures the proper Vary
headers (Origin
, Access-Control-Request-*
) are set to keep caches honest.
Header merging
All generated headers are stored in ctx.req.locals.__corsHeaders
. bunway’s router finalizer merges these onto the final Response
, even if your handler returns a native Response
object:
app.get("/raw", () => new Response("raw", { status: 202 }));
Options reference
| Option | Type | Default | Description | | --------------------- | -------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------ | ----- | ------------- | | origin
| "\*" \| true \| string \| RegExp \| (string | RegExp)[] \| (origin, ctx) => string | false
| "*"
| Origin policy | | credentials
| boolean
| false
| Enable credentialed requests | | methods
| string[]
| ['GET','HEAD','PUT','PATCH','POST','DELETE','OPTIONS']
| Allowed methods for preflight | | allowedHeaders
| string[]
| undefined
| Force allow-list of headers instead of echoing request | | exposedHeaders
| string[]
| undefined
| Values for Access-Control-Expose-Headers
| | maxAge
| number
| 600
| Preflight cache duration | | allowPrivateNetwork
| boolean
| false
| Enable Access-Control-Allow-Private-Network
|
Recommendations
- Reflect (
origin: true
) when you need credentials. - Keep the allow-list tight in production—prefer regex/string arrays over wildcards.
Production allow list
Audit CORS settings regularly. Accidentally allowing *
with credentials or forgetting to restrict origins can expose sensitive endpoints.
- Combine with
errorHandler()
to log disallowed origins or unexpected headers.
For type details see CORSOptions
in the API Reference.