auth0 / nextjs-auth0

Next.js SDK for signing in with Auth0

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CORS preflight OPTIONS request excludes Authorization headers and thus fails auth check

WesleyKapow opened this issue · comments

Checklist

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

  1. Setup an endpoint guarded by withMiddlewareAuthRequired.
  2. Add CORS headers.
  3. Try and use that endpoint from third party domain.

OR

  1. Setup an endpoint guarded by withMiddlewareAuthRequired.
  2. 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.

if (!session?.user) {
if (pathname.startsWith('/api')) {
return NextResponse.json(
{
error: 'not_authenticated',
description: 'The user does not have an active session or is not authenticated'
},
{ status: 401 }
);
}
return NextResponse.redirect(new URL(`${login}?returnTo=${encodeURIComponent(returnTo)}`, origin));
}

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!