cors-headers
v1.0.0
Published
A CORS module using standard browser API
Readme
cors-headers
A browser compatible package for providing a middleware-like function that can be used to get appropriate CORS headers with various options.
Installation
This module is available through the npm registry. Install it using your package manager:
$ pnpm add cors-headersUsage
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
RequestandHeadersAPI.
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 });
},
};Configuring CORS
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 });
},
};Configuring CORS with Dynamic Origin
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 });
},
};Enabling CORS Pre-Flight
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 });
}
// ...
},
};Configuring CORS Asynchronously
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 });
},
};Configuration Options
origin
Configures the Access-Control-Allow-Origin CORS header. Possible values:
Boolean- setorigintotrueto reflect the request origin, as defined byreq.headers.get('Origin'), or set it tofalseto disable CORS.String- setoriginto a specific origin. For example if you set it tohttp://example.comonly requests fromhttp://example.comwill be allowed.RegExp- setoriginto 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- setoriginto an array of valid origins. Each origin can be aStringor aRegExp. For example["http://example1.com", /\.example2\.com$/]will accept any request fromhttp://example1.comor from a subdomain ofexample2.com.Function- setoriginto 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 oforiginoption except a function.
allowedMethods
Configures the Access-Control-Allow-Methods CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: ['GET', 'PUT', 'POST']).
allowedHeaders
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.
exposedHeaders
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.
credentials
Configures the Access-Control-Allow-Credentials CORS header. Set to true to pass the header, otherwise it is omitted.
maxAge
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.
License
Acknowledgement
The code is taken from Express' cors() middleware and modified to use browser compatible Request and Headers API. Credit goes to the original authors.
