CORS preflight OPTIONS request excludes Authorization headers and thus fails auth check
WesleyKapow opened this issue · comments
Checklist
- The issue can be reproduced in the nextjs-auth0 sample app (or N/A).
- I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
- I have looked into the API documentation and have not found a suitable solution or answer.
- I have searched the issues and have not found a suitable solution or answer.
- I have searched the Auth0 Community forums and have not found a suitable solution or answer.
- I agree to the terms within the Auth0 Code of Conduct.
Description
Cannot use CORS and withMiddlewareAuthRequired
together. The issue is that browsers send a preflight OPTIONS request to check with the 3rd party server if CORS is allowed. When doing so, browsers exclude user credentials like Authorization
headers. This means these OPTIONS requests get caught by the auth middleware and rejected.
I believe we need an option (or default) where withMiddlewareAuthRequired
will ignore OPTIONS request.. or at least pass the handling to the provided function so that in user space we can do:
export default withMiddlewareAuthRequired(async (req) => {
if (req.method === "OPTIONS") {
new Response({
status: 200,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization"
}
})
}
... auth code
});
Example of request headers sent by browser for preflight OPTIONS (note no Authorization
header.. as far as I know, these are sent by the browser and there isn't a way to add headers to these preflight requests).
authority: example.com
:method: OPTIONS
:path: /report/metric
:scheme: https
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: POST
Cache-Control: no-cache
Origin: https://example.com
Pragma: no-cache
Referer: https://example.com/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Reproduction
- Setup an endpoint guarded by
withMiddlewareAuthRequired
. - Add CORS headers.
- Try and use that endpoint from third party domain.
OR
- Setup an endpoint guarded by
withMiddlewareAuthRequired
. - Replicate preflight request:
curl -X OPTIONS http://localhost:3001/api/cors-test
and confirm it is rejected by auth.
Additional context
This is where the middleware checks if there's a session (which for OPTIONS preflight requests there isn't) and fails before ever calling the provided function to withMiddlewareAuthRequired
.
nextjs-auth0/src/helpers/with-middleware-auth-required.ts
Lines 115 to 126 in 9496916
Looking through the support forum, I can see a handful of others that have hit this problem:
https://community.auth0.com/t/url-has-been-blocked-by-cors-policy-method-patch-is-not-allowed-by-access-control-allow-methods-in-preflight-response/76763
nextjs-auth0 version
3.1 & latest
Next.js version
13.5.6
Node.js version
v18.11.0
Workaround: We're opting to add our CORS endpoints to config.matcher
to skip them from this middleware and then do manual authentication within those endpoints. It'd be far better if we could use middleware to have a single place for auth and for adding CORS headers for these endpoints.
Hi @WesleyKapow
If you don't want to include options requests you can do:
const handler = withMiddlewareAuthRequired();
export default (req) => {
if (req.method !== 'OPTIONS') return handler(req);
}
I don't think we need a specific option for this, so closing
That'll do it! Thanks for the speedy response!