I’m using express to handle my routes and have CORS enabled for some routes, due to needing to send custom headers and complex request types.
On app start, I do the following:
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
res.setHeader("Access-Control-Allow-Headers", `X-Requested-With, Content-Type, ${customHeaders.join(", ")}`);
res.setHeader("Access-Control-Allow-Credentials", true);
next();
});
My routes look something like:
router.get("api/v1/user/current", customerMiddleware, controllers.Customer.get)
My application can be hosted on my clients’ websites, with each client being able to set the Origin Urls that they’ll be using my application from. These custom Origin Urls are saved on a customer basis.
I have a middleware on my route which checks the Authorization and the customer’s unique token (sent via custom header). Once they’ve been auth’d, I add their customer data onto the request object, something like:
const customer = await getCustomerByToken(req.headers['Customer-Token']);
const origin = req.headers.origin;
const { allowOriginUrls = [] } = customer;
if (allowOriginUrls.includes(origin)
|| whiteListedOrigins.includes(origin)
|| whiteListedOrigins[0] === "*"
) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
req.customer = customer
Eventually, if the request coming in is CORS enabled, then this middleware will look through the customer’s custom origin urls, and set the Allow Origin header to be the referrer url if it’s found.
Currently, the server sends “*” as the Allowed Origin as the default, when it would be overwritten with the above middleware if successful.
My issue is that, because the customer’s unique token is sent via the custom header, this isn’t available in the preflight OPTIONS request, meaning I never have the data to send the customer’s origin url in the response. Resulting in:
Access to XMLHttpRequest at 'https://serverdomain.com/api/v1/users/current' from origin 'https://clientdomain.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Is there a way that I’m able to somehow identify which customer is requesting the route during the Preflight OPTIONS request so I can provide the proper origin url in the response?
I tried accessing the request data and headers in the OPTIONS route, but it didn’t include the data that I needed to be able to identify which URL was allowed.
I recognised that I could just respond with the referrer url sent with the OPTIONS request, but that makes my custom Origin Urls kind of redundant, as the app would be allowed to request from any site that it’s included on.