@supabase/middleware/corsCORS for Web Fetch handlers — answers the OPTIONS preflight and stamps Access-Control-* headers onto your handler's response.
This is the worked example of the response seam. CORS is the textbook case for it: it acts on the request (preflight) and the response (headers).
withCorsis written as anasync function*so it can do both in one middleware — readwith-cors.tsalongside the core README.
import { withCors } from '@supabase/middleware/cors'
export default {
fetch: withCors(
{ origin: ['https://app.example.com'], credentials: true },
async () => Response.json({ ok: true }),
),
}
| Field | Type | Description |
|---|---|---|
origin |
string | string[] | '*' | ((origin: string | null) => boolean) |
Allowed origin(s). Default '*'. With credentials, the request Origin is reflected. |
methods |
string[]? |
Methods advertised on preflight. Default: the common verbs. |
allowedHeaders |
string[]? |
Headers advertised on preflight. Omit to reflect Access-Control-Request-Headers. |
exposedHeaders |
string[]? |
Response headers exposed to the client beyond the safelist. |
credentials |
boolean? |
Send Access-Control-Allow-Credentials: true. Default false. |
maxAge |
number? |
Access-Control-Max-Age (seconds) for preflight caching. |
optionsSuccessStatus |
number? |
Status for a successful preflight. Default 204. |
It contributes ctx.cors.allowedOrigin (the resolved Access-Control-Allow-Origin, or null when the origin isn't allowed) for handlers that want to branch on it.
OPTIONS + Access-Control-Request-Method) short-circuits before the handler runs and returns 204.'*' is forbidden by the Fetch spec, so when both are set the request's Origin is reflected instead of a literal *.Vary: Origin is set whenever the allow-origin is per-origin (anything but a literal *), so shared caches don't serve one origin's response to another.fetch) is handled and a streaming body passes through untouched.This is a small, practical implementation, not a spec-exhaustive one. If you need private-network access, complex header negotiation, or per-route policies, compose your own withCors-shaped middleware — it's ~20 lines.