packages/cors-middleware/README.md
CORS middleware for Remix. It adds standard CORS response headers to Fetch API servers and can either short-circuit preflight requests or pass them through to app-defined OPTIONS handlers.
OPTIONS preflight requestsnpm i remix
import { createRouter } from 'remix/fetch-router'
import { cors } from 'remix/cors-middleware'
let router = createRouter({
middleware: [
cors({
origin: ['https://app.example.com', 'https://admin.example.com'],
credentials: true,
exposedHeaders: ['X-Request-Id'],
}),
],
})
router.get('/api/projects', () => {
return Response.json([{ id: 'p1', name: 'Remix' }], {
headers: {
'X-Request-Id': 'req_123',
},
})
})
origin supports:
'*' to allow all originsstring for a single exact originRegExp for pattern-based matchingArray<string | RegExp> for multiple exact and pattern matchestrue to reflect the request origin(origin, context) => boolean | string for dynamic policieslet router = createRouter({
middleware: [
cors({
origin: ['https://app.example.com', 'https://admin.example.com'],
credentials: true,
}),
],
})
let router = createRouter({
middleware: [
cors({
origin(origin, context) {
if (context.url.pathname.startsWith('/public/')) {
return '*'
}
return origin.endsWith('.trusted.example')
},
}),
],
})
By default, preflight requests are short-circuited with status 204.
let router = createRouter({
middleware: [
cors({
methods: ['GET', 'POST', 'PATCH'],
allowedHeaders: ['Authorization', 'Content-Type'],
maxAge: 600,
}),
],
})
Use a function-based allowedHeaders policy when the header allowlist depends on the request:
let router = createRouter({
middleware: [
cors({
allowedHeaders(request) {
let requestedHeaders = request.headers.get('Access-Control-Request-Headers')
if (requestedHeaders?.includes('x-admin-token')) {
return ['Authorization', 'Content-Type', 'X-Admin-Token']
}
return ['Authorization', 'Content-Type']
},
}),
],
})
Function-based allowedHeaders responses vary on Access-Control-Request-Headers, so caches do not reuse a preflight response for a different requested-header set.
Set preflightContinue: true to let downstream handlers process preflight requests. Use preflightStatusCode when you want short-circuited preflight responses to return a status other than 204.
let router = createRouter({
middleware: [
cors({
allowPrivateNetwork: true,
}),
],
})
When allowPrivateNetwork is enabled, the middleware adds Access-Control-Allow-Private-Network: true for preflight requests that ask for private network access.
let router = createRouter({
middleware: [
cors({
exposedHeaders: ['X-Request-Id', 'X-Trace-Id'],
}),
],
})
credentials: true is used with origin: '*', the middleware reflects the request origin and adds Vary: Origin so the response stays cache-safe.allowedHeaders is a function, preflight responses vary on Access-Control-Request-Headers so caches do not reuse a response for a different requested-header set.preflightContinue and preflightStatusCode only affect how preflight OPTIONS requests are handled. They do not change actual request authorization.cop-middleware - Browser-origin protection middleware for unsafe cross-origin requestsfetch-router - Router for the web Fetch APIheaders - Typed HTTP header utilitiesSee LICENSE