Connect middleware for setting Access-Control headers
Switch branches/tags
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


Build Status

ach is a connect/express middleware generator for setting Access-Control headers for Cross-Origin Resource Sharing.

What is Cross-Origin Resource Sharing (CORS)?

CORS is a set of headers you can set on a response to declare that it's OK for content on other origins (domains) to make certain requests to your site through the browser that would not normally be allowed (like requests with credentials, or JSON POSTs), and to read the response from these cross-origin requests (which would normally be disallowed). See the W3C Specification, and the MDN documentation.

Does Cross-Origin Resource Sharing prevent unauthorized requests?

No. Responding with Access-Control headers only serves as a mechanism to communicate to user's browsers when they should allow sites on other domains to make requests from that user's browser to your server. These sites can already trigger simple requests to your domain from the browser: CORS only allows more complex requests through a mechanism like XMLHttpRequest that would otherwise be blocked by default.

This is the standard-dictated behavior for browsers: other user agents (for instance, a request in Node.js) can make whatever requests they want, including any value for the Origin header that they wish.

Actually restricting access to a server requires an authentication mechanism, the nature of which depends on who and what you're looking to restrict access to. For example, OAuth is a frequently implemented mechanism for authenticating API consumers.


To use ach with Express >=3.x, mount it on whatever path you want to make available with CORS, using either app.use([prefix]) or app.all(route), depending on when you want the middleware to run relative to Express's router.

var app = require('express')();
app.get(function(req,res){res.send('You can read me anywhere!')});

Note that attaching this middleware to a route for a single method (like app.get) will not work for preflighted requests, which make an OPTIONS request before making the preflighted request. You may work around this by attaching the middleware to a corresponding app.options route, but, for the simplest approach, attach it for all methods with app.use or app.all.


By default, ach sets the Access-Control-Allow-Origin to '*' (all servers) and the Access-Control-Allow-Headers to 'X-Requested-With' (to allow XMLHttpRequest to declare itself). Either of these can be overridden (these defaults are only set when their respective options are undefined; notably, if you set the allowOrigin option to a different falsy value (such as null), you will stop any CORS headers from being sent at all).

ach allows you to set a number of headers relevant to the control of CORS to allow behaviors beyond the default. At runtime, ach tweaks the headers it sends slightly to match the expected behavior by the known implementations of CORS in practice (in other words, it polyfills to match what the browsers can handle).

For example, if you had a CDN server with an API route that's meant to serve requests to only your secure site, expose a non-simple header like Link, and allow the DELETE method, you would do something like:

var app = require('express')();
app.all('/api/*', require('ach')({
  allowOrigin: '',
  exposeHeaders: 'Link',
  allowMethods: 'DELETE'
// etc...

ach recognizes option names as either JavaScript-conventional camelCase, or as case-insensitive Header-Style-Hyphen-Separation (optionally beginning with Access-Control). In the presence of multiple equivalent options, the camelCased names take precedence: beyond that, the precedence is undefined, so don't set different values for the same option.

Option / Header Behavior Details


The origin or origins allowed to access this resource with CORS.

This may be either an Array, a space-separated origin-list (including a single origin), '*' (signifying any domain), or null / any other falsy value (which will prevent the setting of Access-Control headers altogether, as mentioned above).

When a request is sent with a Origin header specified, its match status against this option controls whether or not any headers will be sent.

If allowOrigin is set to '*', the headers will be sent: if allowCredentials is not a truthy value, 'Access-Control-Allow-Origin' will be sent as *. If allowCredentials is a truthy value, the 'Access-Control-Allow-Origin' header will be sent with the same value as the request's Origin header, as browsers do not trust the * origin with credentials.

Otherwise, the request's Origin will be compared against the specified list of origins (falsy values and null are interpreted as an empty list). If the passed origin matches a value of the allowOrigin list, the Access-Control headers will be set, with Access-Control-Allow-Origin set to the value of the request's Origin (as browser implementations do not recognize origin lists in practice).

When Access-Control-Allow-Origin is sent with the value of the request's Origin header, unless that Origin is the only one allowed, ach will ensure that the response's Vary header includes Origin to inform caching systems not to cache the response for other origins.

Note that, while allowOrigin accepts the wildcard value '*' in place of an origin-list, listed origins can not use wildcards (if you wish to support multiple domains, ports, or HTTP-and/or-HTTPS, you must explicitly specify each origin). If you need wildcard matching for Origin, you're outside the CORS header specification and, as such, outside the domain of problems ach() aims to solve.


Whether to allow requests with credentials (such as an XMLHttpRequest with withCredentials set to true), or (for GET requests with credentials), whether the client will be allowed to read the results of the request.

Setting this changes the behavior of the wildcard ('*') Access-Control-Allow-Origin header as described above.


A comma-separated list headers on the response to expose to the client.

The "simple response headers" Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, and Pragma are always exposed, so this can only be used to expose other headers on the response.


How many seconds clients should cache these Access-Control rules for.


A comma-separated list of methods to allow requests to use.

The "simple methods" GET, HEAD, and POST are intrinsically allowed, so this can only be used to whitelist other HTTP methods like PUT and DELETE.


A comma-separated list of headers to allow requests to send.

The "simple headers" Accept, Accept-Language, and Content-Language are intrinsically allowed, as is Content-Type when its value is one of application/x-www-form-urlencoded, multipart/form-data, or text/plain, so this can only be used to whitelist other headers.