live-server --cors: reflect the request Origin and allow credentials in development
- tool
- CORS
- command
- live-server
- flag
- --cors
- default
- off (no CORS headers; live-server only serves files and the live-reload script)
npx live-server ./public --cors turns on CORS in the live-reload development server. Unlike http-server --cors and serve -C, which send the wildcard *, live-server echoes the request's Origin into Access-Control-Allow-Origin and adds Access-Control-Allow-Credentials: true. That is the combination browsers require for requests that carry cookies, so a front end on another port can call the files with credentials: 'include'. Preflight requests get the allowed methods and the requested headers back.
Response headers with --cors
A cross-origin GET and a preflight for PUT with an Authorization header:
npm init -y >/dev/null && npm install --silent --no-audit --no-fund live-server@1.2.2 >/dev/null 2>&1
mkdir site && echo '{"ok":true}' > site/data.json
timeout 12 node node_modules/live-server/live-server.js site --port=5421 --host=127.0.0.1 --no-browser --quiet --cors &
sleep 4
echo "--- GET:"
curl -s -D - -o /dev/null -H "Origin: http://localhost:3000" http://127.0.0.1:5421/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control|^vary"
echo "--- preflight:"
curl -s -D - -o /dev/null -X OPTIONS -H "Origin: http://localhost:3000" -H "Access-Control-Request-Method: PUT" \
-H "Access-Control-Request-Headers: Authorization" http://127.0.0.1:5421/data.json | tr -d '\r' | grep -iE "^HTTP|^access-control"
waitOutput
--- GET: HTTP/1.1 200 OK Access-Control-Allow-Origin: http://localhost:3000 Vary: Origin Access-Control-Allow-Credentials: true --- preflight: HTTP/1.1 204 No Content Access-Control-Allow-Origin: http://localhost:3000 Access-Control-Allow-Credentials: true Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE Access-Control-Allow-Headers: Authorization
The allowed origin is exactly http://localhost:3000, the value the request sent. The preflight answer is 204 No Content with a method list and the requested Authorization header mirrored in Access-Control-Allow-Headers.
Three dev servers compared
| Header | live-server --cors | http-server --cors | serve -C |
|---|---|---|---|
| Access-Control-Allow-Origin | The request Origin | * | * |
| Access-Control-Allow-Credentials | true | not sent | true (ignored with *) |
| Access-Control-Allow-Methods (preflight) | GET,HEAD,PUT,PATCH,POST,DELETE | not sent | not sent |
| Access-Control-Allow-Headers (preflight) | The requested headers | Fixed list | * |
| Preflight status | 204 | 204 | 200 |
Use live-server when the page under development sends cookies or HTTP authentication to the files; the other two are enough for anonymous reads of JSON, images or fonts.
Pitfalls
- Cookies still need SameSite. CORS allows the browser to read the response, but a cookie is only sent cross-site if it has
SameSite=None; Secure; betweenlocalhostports the cookie rules for same-site apply. See Set-Cookie SameSite. - Do not copy the pattern to production. Reflecting every origin with credentials allowed lets any site read authenticated data. Real servers should compare the origin with a list and send
Vary: Origin. - Static files only. live-server serves files. A PUT passes the preflight, but the server does not implement it, so the real request comes back with an error status: the app sees a failed request, not a CORS error.
- Project status. live-server 1.2.2 is the current release; for new projects, dev servers built into Vite or webpack have their own CORS settings.
FAQ
Is reflecting the Origin header safe?
For a local development server it is convenient. On a real API, echoing any Origin together with Access-Control-Allow-Credentials: true lets every website read authenticated responses, which defeats the purpose of CORS. Production servers should check the origin against an allow list.
Why does live-server answer with my exact origin instead of *?
Browsers reject Access-Control-Allow-Origin: * for requests that send cookies. Echoing the exact origin is the only way to allow credentialed requests, so live-server copies the Origin header it receives.
Does live-server --cors add Vary: Origin?
Check your version's response headers. When a server reflects the origin, Vary: Origin tells caches that the response differs per origin; without it a shared cache could serve one origin's header to another.