Configure security headers¶
The docs path serves an interactive "try it" console, so by default Register
wraps both the docs and spec handlers with go/transport's conservative
security-header middleware:
X-Content-Type-Options: nosniffX-Frame-Options: DENYandContent-Security-Policy: frame-ancestors 'none'Referrer-Policy: no-referrer- HSTS off (enable it deliberately for HTTPS deployments)
You get this with no configuration:
The console renders and issues try-it requests normally under these defaults — they restrict framing and MIME sniffing, not scripting.
Turn HSTS on for an HTTPS deployment¶
HSTS is off by default because it is only meaningful over TLS, and advertising it from a host that also answers plain HTTP can wedge clients. Enable it deliberately, on a server reachable only over HTTPS:
import (
"time"
transporthttp "gitlab.com/phpboyscout/go/transport/http"
)
openapi.Register(mux, spec,
openapi.WithSecurityHeaderOptions(
transporthttp.WithHSTS(365*24*time.Hour, true, false),
),
)
The arguments are maxAge, includeSubdomains and preload. A non-positive
maxAge leaves HSTS disabled.
Customise the other headers¶
Every go/transport/http SecurityHeadersOption is accepted and forwarded verbatim
to transporthttp.SecurityHeadersMiddleware:
| Option | Default it overrides |
|---|---|
WithContentTypeOptions(value string) |
nosniff |
WithFrameOptions(value string) |
DENY |
WithReferrerPolicy(policy string) |
no-referrer |
WithContentSecurityPolicy(policy string) |
frame-ancestors 'none' |
WithHSTS(maxAge, includeSubdomains, preload) |
(off) |
An empty string omits the header entirely for the first three.
Repeated WithSecurityHeaderOptions calls accumulate rather than replace, so
options from several places in your wiring all apply, last value winning per header.
Allow the docs page to be framed¶
X-Frame-Options: DENY and frame-ancestors 'none' block embedding the docs page
in an <iframe> — including in your own developer portal. Relax both, or neither;
browsers that honour CSP frame-ancestors prefer it to the legacy header:
openapi.Register(mux, spec,
openapi.WithSecurityHeaderOptions(
transporthttp.WithFrameOptions("SAMEORIGIN"),
transporthttp.WithContentSecurityPolicy("frame-ancestors 'self'"),
),
)
Careful with a full Content-Security-Policy¶
WithContentSecurityPolicy replaces the whole header, not just the
frame-ancestors directive — you own the complete policy from then on.
The generated docs page carries an inline style="height: 100vh; margin: 0"
attribute on <body>, and Stoplight Elements injects styles at runtime, so a policy
without 'unsafe-inline' in style-src breaks the page's layout. The default
policy sets only frame-ancestors, which is why it does not.
Opt out¶
If an outer middleware chain already sets equivalent headers, disable the built-in wrapper so headers are not set twice:
Warning
WithoutSecurityHeaders serves the interactive docs UI without
nosniff/frame/referrer protections. Use it only when a surrounding chain
provides them; otherwise keep the default.