1

I have CORS globally configured like this, to handle credentials:

app.use(cors({ origin: 'https://example.com', credentials: true }))

But on certain routes, I need to allow options requests, so following the documentation, I'm doing something like this:

router.options('/someroute', cors())
router.get('/someroute', cors(), someOtherMiddleware, async (req, res) => {
  // do stuff
}

My global CORS policy seems to override the route policy, but only on the options method, I think. I'm trying to come up with a way to make both of these CORS policies play nicely. I have also tried the following, but this doesn't work either. Whichever one I put first seems to override the other one.

app.options('*', cors())
app.use(cors({ origin: 'https://example.com', credentials: true }))
Glenn
  • 4,195
  • 9
  • 33
  • 41
  • 2
    The cors middleware [by default sets up a global `OPTIONS` handler](https://github.com/expressjs/cors/blob/v2.8.5/lib/index.js#L163). Are you saying you want to disable that for some routes? – Phil Nov 30 '21 at 01:06
  • If I understand correctly, in the `app.use()` where I'm setting a specific origin, is that making all options requests require that origin? If so, then yes, I need to disable that for specific routes and allow all origins for options requests. – Glenn Nov 30 '21 at 01:17
  • _"is that making all options requests require that origin?"_ yes, for all cross-origin requests. The request method doesn't really come into it though – Phil Nov 30 '21 at 01:26
  • `app.use()` covers all types of requests including GET, PUT, POST, OPTIONS, HEAD, DELETE etc. – slebetman Nov 30 '21 at 01:30
  • I can't really tell what problem you're asking for help with here. If you have this `app.use(cors({ origin: 'https://example.com', credentials: true }))` specified before all your routes, then it will go into action first and, if it's configured to just handle a pre-flight request for you automatically, then it will just handle it and no other routes will get a chance to look at it. Express routes and middleware are processed in the order they are declared. – jfriend00 Nov 30 '21 at 02:41
  • I think where I'm getting tripped up is on one hand I'm using an Authorization header to pass an API key. I guess Authorization header only gets passed when credentials are set to true, but on the other hand, I need to accept that header from all origins, since it's just an API key. :/ – Glenn Nov 30 '21 at 02:43
  • So, shouldn't the client just set `withCredentials: true` when adding the Authorization custom header and sending the request? – jfriend00 Nov 30 '21 at 03:15
  • See my self-answer below. The app level cors policy wasn't allowing me to set cors policies on any other options requests. You have to set a kind of obscure and poorly documented `preflightContinue` property to do that. – Glenn Nov 30 '21 at 04:12

1 Answers1

1

The reason my 2nd code snippet above wasn't working as expected was because I needed to add the preflightContinue property when setting the cors policy at the app level. Otherwise it will ignore cors policies on options routes set at the route level. Kind of a poorly documented thing.

The final solution was to do this at the app level:

app.use(cors({ 
  origin: 'https://example.com', 
  credentials: true,
  preflightContinue: true,
}))

Now this cors policy on the options route actually works:

router.options('/someroute', cors())
router.get('/someroute', cors(), someOtherMiddleware, async (req, res) => {
  // do stuff
}

Ugh, spent so long figuring this one out. Hope this saves someone some time.

Glenn
  • 4,195
  • 9
  • 33
  • 41