CORS for a SPA
Reflect allowed origins, enable credentials, and list custom headers the browser will send.
Prerequisites
- Front-end on a different origin than the API (e.g. Vite on
:5173) - Decide whether you need cookies / credentialed fetch
Server
import { HttpServer } from "jsr:@webtools/expressapi";
const allowed = new Set([
"http://localhost:5173",
"https://app.example.com",
]);
export const server = new HttpServer()
.cors({
allowOrigin: (req) => {
const origin = req.headers.get("origin");
return origin && allowed.has(origin) ? origin : undefined;
},
allowCredentials: true,
allowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
allowHeaders: "Content-Type, Authorization",
maxAge: "3600",
})
.get("/health", (_req, res) => res.json({ ok: true }))
.post("/echo", (req, res) => res.json({ body: req.body }));
if (import.meta.main) server.listen(5050);Browser fetch
await fetch("http://localhost:5050/echo", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer …",
},
body: JSON.stringify({ hello: "world" }),
});The browser may send an OPTIONS preflight first. ExpressAPI answers with 204 and the merged CORS headers - you do not register OPTIONS yourself.