How to properly implement CORs for API routes - App Directory + Middleware #52933
-
SummaryI have two applications running on localhost. One is running on :1200, the other is :1201. When I make an API request from one application to the other without any CORs configuration I get the following: Access to fetch at 'http://localhost:1201/api/thing' from origin 'http://localhost:1200' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. This is expected as it's a request coming from a different origin than the origin of the endpoint being requested. There seem to be 3 options to implement / adjust CORs to allow for specific or all origins:
They all follow slightly different approaches syntactically but all pretty much work the same way. As I prefer to use Middleware for this sort of thing, this is what my attempt looks like: import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
export async function middleware(req: NextRequest) {
if (req.nextUrl.pathname.startsWith("/api")) {
const res = NextResponse.next()
res.headers.append('Access-Control-Allow-Credentials', "true")
res.headers.append('Access-Control-Allow-Origin', '*')
res.headers.append('Access-Control-Allow-Methods', 'GET,DELETE,PATCH,POST,PUT,OPTIONS')
res.headers.append(
'Access-Control-Allow-Headers',
'X-CSRF-Token, X-Requested-With, Authorisation, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
)
return res
}
}
export const config = {
matcher: "/((?!_next/static|_next/image|favicon.ico|login|setup).*)",
}; This middleware is running on both :1200 and :1201, they have the same CORs setup. If I now reattempt to make this API request, the result is now the following: Access to fetch at 'http://localhost:1201/api/instance' from origin 'http://localhost:1200' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: It does not have HTTP ok status. This is progress, but still not the desired result. What's missing? Is this a bug? Is this user error? Is this lack of docs? Additional informationNo response ExampleNo response |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 13 replies
-
In your browser dev tools, the network most likely has an OPTIONS request that goes to Could you control that you don't reject requests based on the |
Beta Was this translation helpful? Give feedback.
-
@icyJoseph helped point out what the issue was. To summarise with an example: My endpoint being requested only had a Because Before: export const PUT = async (request: NextRequest) => {
// Handle PUT request here
} After: export const PUT = async (request: NextRequest) => {
// Handle PUT request here
}
export const OPTIONS = async (request: NextRequest) => {
return new NextResponse('', {
status: 200
})
} I wasn't sure what to put for the |
Beta Was this translation helpful? Give feedback.
@icyJoseph helped point out what the issue was. To summarise with an example:
My endpoint being requested only had a
PUT
handler, because that's all I needed at the time.Because
preflight
will make anOPTIONS
request to the same endpoint, if there's noOPTIONS
handler then CORs fails.Before:
After:
I wasn't sure what to put for the
body
of theOPTIONS
handler but the answer serves its purpose.