diff --git a/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx b/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx index 450a873dcdbed..122a4c620e8de 100644 --- a/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx +++ b/docs/02-app/01-building-your-application/01-routing/12-route-handlers.mdx @@ -572,7 +572,7 @@ Since `formData` data are all strings, you may want to use [`zod-form-data`](htt ### CORS -You can set CORS headers on a `Response` using the standard Web API methods: +You can set CORS headers for a specific Route Handler using the standard Web API methods: ```ts filename="app/api/route.ts" switcher export const dynamic = 'force-dynamic' // defaults to auto @@ -604,6 +604,11 @@ export async function GET(request) { } ``` +> **Good to know**: +> +> - To add CORS headers to multiple Route Handlers, you can use [Middleware](/docs/app/building-your-application/routing/middleware#cors) or the [`next.config.js` file](/docs/app/api-reference/next-config-js/headers#cors). +> - Alternatively, see our [CORS example](https://github.com/vercel/examples/blob/main/edge-functions/cors/lib/cors.ts) package. + ### Webhooks You can use a Route Handler to receive webhooks from third-party services: diff --git a/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx b/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx index 2625c25101390..2091aec5a3e03 100644 --- a/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx +++ b/docs/02-app/01-building-your-application/01-routing/13-middleware.mdx @@ -313,6 +313,106 @@ export function middleware(request) { > **Good to know**: Avoid setting large headers as it might cause [431 Request Header Fields Too Large](https://developer.mozilla.org/docs/Web/HTTP/Status/431) error depending on your backend web server configuration. +### CORS + +You can set CORS headers in Middleware to allow cross-origin requests, including [simple](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) and [preflighted](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#preflighted_requests) requests. + +```tsx filename="middleware.ts" switcher +import { NextRequest, NextResponse } from 'next/server' + +const allowedOrigins = ['https://acme.com', 'https://my-app.org'] + +const corsOptions = { + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', +} + +export function middleware(request: NextRequest) { + // Check the origin from the request + const origin = request.headers.get('origin') ?? '' + const isAllowedOrigin = allowedOrigins.includes(origin) + + // Handle preflighted requests + const isPreflight = request.method === 'OPTIONS' + + if (isPreflight) { + const preflightHeaders = { + ...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }), + ...corsOptions, + } + return NextResponse.json({}, { headers: preflightHeaders }) + } + + // Handle simple requests + const response = NextResponse.next() + + if (isAllowedOrigin) { + response.headers.set('Access-Control-Allow-Origin', origin) + } + + Object.entries(corsOptions).forEach(([key, value]) => { + response.headers.set(key, value) + }) + + return response +} + +export const config = { + matcher: '/api/:path*', +} +``` + +```jsx filename="middleware.js" switcher +import { NextResponse } from 'next/server' + +const allowedOrigins = ['https://acme.com', 'https://my-app.org'] + +const corsOptions = { + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', +} + +export function middleware(request) { + // Check the origin from the request + const origin = request.headers.get('origin') ?? '' + const isAllowedOrigin = allowedOrigins.includes(origin) + + // Handle preflighted requests + const isPreflight = request.method === 'OPTIONS' + + if (isPreflight) { + const preflightHeaders = { + ...(isAllowedOrigin && { 'Access-Control-Allow-Origin': origin }), + ...corsOptions, + } + return NextResponse.json({}, { headers: preflightHeaders }) + } + + // Handle simple requests + const response = NextResponse.next() + + if (isAllowedOrigin) { + response.headers.set('Access-Control-Allow-Origin', origin) + } + + Object.entries(corsOptions).forEach(([key, value]) => { + response.headers.set(key, value) + }) + + return response +} + +export const config = { + matcher: '/api/:path*', +} +``` + + + +> **Good to know:** You can configure CORS headers for individual routes in [Route Handlers](/docs/app/building-your-application/routing/route-handlers#cors). + + + ## Producing a Response You can respond from Middleware directly by returning a `Response` or `NextResponse` instance. (This is available since [Next.js v13.1.0](https://nextjs.org/blog/next-13-1#nextjs-advanced-middleware)) diff --git a/docs/02-app/02-api-reference/05-next-config-js/headers.mdx b/docs/02-app/02-api-reference/05-next-config-js/headers.mdx index 0576571667889..d8ed4ee398311 100644 --- a/docs/02-app/02-api-reference/05-next-config-js/headers.mdx +++ b/docs/02-app/02-api-reference/05-next-config-js/headers.mdx @@ -429,6 +429,34 @@ export default function handler(req, res) { ## Options +### CORS + +[Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/docs/Web/HTTP/CORS) is a security feature that allows you to control which sites can access your resources. You can set the `Access-Control-Allow-Origin` header to allow a specific origin to access your API EndpointsRoute Handlers. + +```js +async headers() { + return [ + { + source: "/api/:path*", + headers: [ + { + key: "Access-Control-Allow-Origin", + value: "*", // Set your origin + }, + { + key: "Access-Control-Allow-Methods", + value: "GET, POST, PUT, DELETE, OPTIONS", + }, + { + key: "Access-Control-Allow-Headers", + value: "Content-Type, Authorization", + }, + ], + }, + ]; + }, +``` + ### X-DNS-Prefetch-Control [This header](https://developer.mozilla.org/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control) controls DNS prefetching, allowing browsers to proactively perform domain name resolution on external links, images, CSS, JavaScript, and more. This prefetching is performed in the background, so the [DNS](https://developer.mozilla.org/docs/Glossary/DNS) is more likely to be resolved by the time the referenced items are needed. This reduces latency when the user clicks a link.