Secure headers
security.headers replaces a default value, or turns a header off with false.
security.headers replaces a default value, or turns a header off with false. security.headers: false turns
all of them off. Two headers are not sent unless you ask: Cross-Origin-Opener-Policy and Cross-Origin-Resource-Policy
(crossOriginOpenerPolicy, crossOriginResourcePolicy). HSTS is opt-in and is added only when the request came
over https, so a development server on http://localhost never sends it.
| Option | Header | Default |
|---|---|---|
contentTypeOptions |
X-Content-Type-Options |
nosniff |
referrerPolicy |
Referrer-Policy |
strict-origin-when-cross-origin |
permissionsPolicy |
Permissions-Policy |
DEFAULT_PERMISSIONS_POLICY (accelerometer, camera, geolocation, gyroscope, magnetometer, microphone, payment and usb off) |
frameOptions |
X-Frame-Options |
SAMEORIGIN; also "DENY" |
crossOriginOpenerPolicy |
Cross-Origin-Opener-Policy |
not sent |
crossOriginResourcePolicy |
Cross-Origin-Resource-Policy |
not sent |
hsts |
Strict-Transport-Security |
not sent; { maxAge, includeSubDomains?, preload? } |
A header the route already set wins: the handler adds a security header only when the response does not have it.
secureHeaderEntries is the pure function behind this, so the result of a configuration can be read without a
request.
src/routes/api/widget.tsts
import { html } from "@shadow-js/dusk/server";
/** A page that is meant to be framed by its own site only; it says so itself. */
export const GET = () => html("<p>widget</p>", { headers: { "x-frame-options": "DENY" } });