Cross-Origin Resource Sharing (CORS) issues are common when you are hosting your backend and frontend applications on different origins. Browsers implement the CORS mechanism as a safeguard to prevent applications on a different origin from loading your resources. This is why it is important to set up your backend application with the correct CORS configuration.
Getting Started
When using Vercel, you can configure CORS headers in the following ways:
- Using the Vercel project configuration
- Using the Edge Middleware
- Using framework configuration
- Route handler configuration
This post uses the code snippets from the cors-example GitHub repository, which showcases working examples of CORS configuration in popular web frameworks such as Next.js, Nuxt, Astro, and Flask deployed on Vercel.
Using the Vercel project configuration
You can use the headers configuration option in the vercel.json
file of your project to add CORS headers. For example, the following configuration will add the CORS headers to all responses from the /vercel-config-cors
endpoint.
{
"headers": [
{
"source": "/vercel-config-cors",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "https://rrv7.vercel.app"
},
{
"key": "Access-Control-Allow-Methods",
"value": "GET, POST, PUT, DELETE, OPTIONS"
},
{
"key": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
]
}
Using the Edge Middleware
The Edge Middleware provides a fast and efficient way to modify headers on the requests and responses of your applications. For example, the middleware.ts from an Astro project adds the appropriate CORS headers to the requests coming to the /mw-cors
endpoint without changing the endpoint handler code. To view the complete code, see this GitHub repository.
import { next } from "@vercel/edge";
const allowedOrigins = ["https://rrv7.vercel.app"];
const corsOptions = {
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
export default function middleware(request: 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 Response.json({ preflight: true }, { headers: preflightHeaders });
}
// Handle simple requests
const response = new Response();
if (isAllowedOrigin) {
response.headers.set("Access-Control-Allow-Origin", origin);
}
Object.entries(corsOptions).forEach(([key, value]) => {
response.headers.set(key, value);
});
return next(response);
}
export const config = {
matcher: "/mw-cors",
};
Using framework configuration
Many frameworks such as Next.js and Nuxt provide easy APIs to add CORS headers from the config file. For example, the following nuxt.config.ts sets routeRules
for a specific route (/api/nuxt-config-cors
) to send the CORS headers automatically for all the requests made to this endpoint.
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
devtools: { enabled: true },
routeRules: {
"/api/nuxt-config-cors": {
headers: {
"Access-Control-Allow-Origin": "https://rrv7.vercel.app",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
},
},
});
Route handler configuration
At last, you can always return the CORS headers from the route handler response. For example, the following Next.js route handler adds the headers to the endpoint response.
export async function GET() {
return new Response("Hello, Next.js!", {
status: 200,
headers: {
"Access-Control-Allow-Origin": "https://rrv7.vercel.app",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Custom-Header",
},
});
}
Troubleshooting common issues
Incorrect allow origin header
The Access-Control-Allow-Origin lets the server define which origin is allowed to send a cross-origin request. It is important to ensure that the origin value must matches all three aspects: scheme, hostname, and port of the incoming request’s Origin
header.
Incorrect HTTP methods
The Access-Control-Allow-Methods header tells the browser about the HTTP methods that the server supports. For example, it can become an issue when your frontend application is making an HTTP request that triggers a Preflight request and you don’t support the OPTIONS
request method, which is used by browsers to check if CORS is supported.
Missing allowed headers
It’s common to overlook the additional headers or custom headers that your frontend application might be sending along with the requests to your backend. The Access-Control-Allow-Headers header lets your server define a list of headers that are allowed for cross-origin requests.
Missing credentials header
By default, CORS doesn’t allow cookies
with cross-origin requests, which will lead to errors in your application. To allow credentials to be sent with your requests you need to:
-
Allow credentials on CORS in your server code by sending the Access-Control-Allow-Credentials header. For example, the following Flask application specifies
supports_credentials=True
to allow sending credentials.from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app, supports_credentials=True, resources={r"/api/cors": {"origins": "https://rrv7.vercel.app"}})
-
Update your
fetch
call to includecredentials
with the request, as follows:const response = await fetch(url, { method: 'GET', credentials: 'include', // This tells fetch to include credentials headers: { 'Content-Type': 'application/json', } });