A browser compatible package for providing a middleware-like function that can be used to get appropriate CORS headers with various options.
This module is available through the npm registry. Install it using your package manager:
$ pnpm add cors-headers
The cors()
function returns an object with headers key (which is a Headers
instance) containing relevant CORS headers for the processed Request.
Note
The code below shows the usage of this module inside of Cloudflare Workers, but using this in any environment should be fine as long as the environment supports browser compatible Request
and Headers
API.
import { cors } from "cors-headers";
export default {
async fetch(req: Request): Promise<Response> {
const { headers } = cors(req);
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers });
}
// reuse the headers to return CORS enabled Responses
return new Response("Hello World!", { status: 200, headers });
},
};
import { cors } from "cors-headers";
export default {
async fetch(req: Request): Promise<Response> {
const { headers } = cors(req, { origin: "https://example.com" });
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers });
}
// ... some other logic
return new Response("Hello example.com!", { status: 200, headers });
},
};
This module supports validating the origin dynamically using a function provided
to the origin
option. This function will receive a string that is the request origin
(or null
if the request has no origin), with the signature
callback(origin)
.
The origin
callback should return any value allowed for the origin
option of the module, except a function. See the
configuration options section for more information on all
the possible value types.
This function is designed to allow the dynamic loading of allowed origin(s) from any other source, like a database:
import { cors } from "cors-headers";
export default {
async fetch(req: Request): Promise<Response> {
// allowlist is an example data to get a list of origins from a your db
const allowlist = ["http://example1.com", "http://example2.com"];
const { headers } = cors(req, {
origin: (reqOrigin) => {
if (reqOrigin && allowlist.indexOf(reqOrigin) !== -1) {
return true; // reflect (enable) the requested origin in the CORS response
}
return false; // else disable CORS
},
});
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers });
}
// This response is CORS enabled for allowed domains
return new Response("hello origin from db!", { status: 200, headers });
},
};
Certain CORS requests are considered 'complex' and require an initial
OPTIONS
request (called the "pre-flight request"). An example of a
'complex' CORS request is one that uses an HTTP verb other than
GET
/HEAD
/POST
(such as DELETE
) or that uses custom headers. To enable
pre-flighting, you must handle OPTIONS
requests:
import { cors } from "cors-headers";
export default {
async fetch(req: Request): Promise<Response> {
const { headers } = cors(req, {
allowedMethods: ["DELETE"],
});
// pre-flight requests
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers });
}
// ...
},
};
import { cors, type CORSOptionsCallback } from "cors-headers";
export default {
async fetch(req: Request): Promise<Response> {
const allowlist = ["http://example1.com", "http://example2.com"];
const dynamicCORSOptions: CORSOptionsCallback = (origin) => {
if (origin && allowlist.indexOf(origin) !== -1) {
return { origin: true, maxAge: 123 }; // reflect (enable) the requested origin in the CORS response
} else {
return { origin: false }; // disable CORS for this request
}
};
const { headers } = cors(req, dynamicCORSOptions);
if (req.method === "OPTIONS") {
return new Response(null, { status: 204, headers });
}
// This response is CORS enabled for allowed domains
return new Response("Hello dynamic origin opts!", { status: 200, headers });
},
};
Configures the Access-Control-Allow-Origin
CORS header. Possible values:
-
Boolean
- setorigin
totrue
to reflect the request origin, as defined byreq.headers.get('Origin')
, or set it tofalse
to disable CORS. -
String
- setorigin
to a specific origin. For example if you set it tohttp://example.com
only requests fromhttp://example.com
will be allowed. -
RegExp
- setorigin
to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern/example\.com$/
will reflect any request that is coming from an origin ending withexample.com
. -
Array
- setorigin
to an array of valid origins. Each origin can be aString
or aRegExp
. For example["http://example1.com", /\.example2\.com$/]
will accept any request fromhttp://example1.com
or from a subdomain ofexample2.com
. -
Function
- setorigin
to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (called ascallback(origin)
. It should return allowed values oforigin
option except a function.
Configures the Access-Control-Allow-Methods
CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST'
) or an array (ex: ['GET', 'PUT', 'POST']
).
Configures the Access-Control-Allow-Headers
CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization'
) or an array (ex: ['Content-Type', 'Authorization']
). If not specified, defaults to reflecting the headers specified in the request's Access-Control-Request-Headers
header.
Configures the Access-Control-Expose-Headers
CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range'
) or an array (ex: ['Content-Range', 'X-Content-Range']
). If not specified, no custom headers are exposed.
Configures the Access-Control-Allow-Credentials
CORS header. Set to true
to pass the header, otherwise it is omitted.
Configures the Access-Control-Max-Age
CORS header. Set to an integer to pass the header, otherwise it is omitted.
The default configuration is:
{
"origin": "*",
"allowedMethods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"credentials": false
}
For details on the effect of each CORS header, read this article on web.dev.
The code is taken from Express' cors()
middleware and modified to use browser compatible Request
and Headers
API. Credit goes to the original authors.