@remix-run/cors-middleware
v0.2.0
Published
Middleware for handling CORS in Fetch API servers
Maintainers
Readme
cors-middleware
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.
Features
- Preflight Handling - Automatically handles
OPTIONSpreflight requests - Flexible Origin Rules - Supports static, regex, list, and function-based origin policies
- Credential Support - Supports credentialed requests with spec-safe origin reflection
- Header Controls - Configure allowed and exposed headers, preflight methods, and max age
- Private Network Support - Optionally allow private network preflight requests
Installation
npm i remixUsage
import { createRouter } from 'remix/router'
import { cors } from 'remix/middleware/cors'
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 Policies
origin supports:
'*'to allow all originsstringfor a single exact originRegExpfor pattern-based matchingArray<string | RegExp>for multiple exact and pattern matchestrueto reflect the request origin(origin, context) => boolean | stringfor dynamic policies
When origin is omitted, it defaults to '*'. This implicit default is not reflected when credentials are enabled. Configure an explicit origin policy for credentialed cross-origin requests.
Restrict Origins
let router = createRouter({
middleware: [
cors({
origin: ['https://app.example.com', 'https://admin.example.com'],
credentials: true,
}),
],
})Dynamic Origin Policies
let router = createRouter({
middleware: [
cors({
origin(origin, context) {
if (context.url.pathname.startsWith('/public/')) {
return '*'
}
return origin.endsWith('.trusted.example')
},
}),
],
})Preflight Behavior
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.
Private Network Preflights
let router = createRouter({
middleware: [
cors({
allowPrivateNetwork: true,
}),
],
})Private network access is disabled by default. When allowPrivateNetwork is enabled, the middleware adds Access-Control-Allow-Private-Network: true for preflight requests that ask for private network access and pass the origin policy. The default origin: '*' allows all origins; configure origin to limit which origins can request private network access.
With this option enabled, preflight responses vary on Access-Control-Request-Private-Network, including when the request header is absent or does not request access.
Expose Response Headers
let router = createRouter({
middleware: [
cors({
exposedHeaders: ['X-Request-Id', 'X-Trace-Id'],
}),
],
})Caveats
- CORS is primarily a browser enforcement mechanism. Disallowed non-preflight requests still reach your handlers unless you add separate request validation.
- When
credentials: trueis used without an explicitorigin, the middleware preserves the defaultAccess-Control-Allow-Origin: *header. Browsers do not expose credentialed responses with a wildcard allowed origin, so configure an explicit origin policy to allow them. - When
credentials: trueis used with an explicitorigin: '*', the middleware reflects the request origin and addsVary: Originso the response stays cache-safe. - When
allowedHeadersis a function, preflight responses vary onAccess-Control-Request-Headersso caches do not reuse a response for a different requested-header set. preflightContinueandpreflightStatusCodeonly affect how preflightOPTIONSrequests are handled. They do not change actual request authorization.
Related Packages
cop-middleware- Browser-origin protection middleware for unsafe cross-origin requestsfetch-router- Router for the web Fetch APIheaders- Typed HTTP header utilities
Related Work
License
See LICENSE
