Plugins

Security Headers

Official plugin — the complete secure-headers set on every HTTP response, failures included. Full helmet.js parity with API-first defaults, a CSP builder with report-only mode, and live DB-driven config.

securityHeaders() stamps security headers on every HTTP flow response — successes, failures, and short-circuits alike, because it runs at onResponse, the last pipeline stage. An explicit value your app already set is never overridden unless you ask for it.

Quick start

src/app.ts
import { oke } from "okengine";
import { securityHeaders } from "okengine/plugins";

export const app = oke({ name: "shop", env: "dev" }).plug(securityHeaders());

Every HTTP response now carries:

HeaderValue
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
Referrer-Policyno-referrer
Origin-Agent-Cluster?1
X-DNS-Prefetch-Controloff
X-Download-Optionsnoopen
X-Permitted-Cross-Domain-Policiesnone
X-XSS-Protection0
X-Powered-Byremoved

Helmet parity

Every helmet.js middleware maps to an option here — same defaults wherever helmet's default is safe for an API, plus three deliberate deviations marked opt-in:

Helmet middlewareThis pluginDefault match?
contentSecurityPolicycontentSecurityPolicy — string or { directives, useDefaults, reportOnly } builderSame default directives; ours is opt-in like helmet's structure suggests
crossOriginEmbedderPolicycrossOriginEmbedderPolicyYes — off unless set
crossOriginOpenerPolicycrossOriginOpenerPolicyopt-in — helmet's same-origin default breaks cross-origin API clients
crossOriginResourcePolicycrossOriginResourcePolicyopt-in — same API rationale
originAgentClusteroriginAgentClusterYes — ?1
referrerPolicyreferrerPolicyYes — no-referrer
strictTransportSecurityhstsopt-in — HSTS is sticky; never on plain-HTTP local dev
xContentTypeOptionsalways onYes — nosniff
xDnsPrefetchControldnsPrefetchControlYes — off; { allow: true }on
xDownloadOptionsdownloadOptionsYes — noopen
xFrameOptionsframeOptionsYes — stricter: DENY over helmet's SAMEORIGIN
xPermittedCrossDomainPoliciespermittedCrossDomainPoliciesYes — none
xPoweredBypoweredByYes — removed; a string sets a decoy value
xXssProtectionxssProtectionYes — 0 (disables the legacy buggy auditor)

Beyond parity: headers land on failures too (helmet middleware ordering bugs are a classic Express footgun), app-set values win by default, and every option can be driven live from the database (below).

Options

OptionTypeDefaultDoes
contentSecurityPolicystring · { directives, useDefaults?, reportOnly? }— (omitted)CSP header; object form merges over helmet's default directives, camelCase or kebab keys
frameOptions"DENY" · "SAMEORIGIN""DENY"X-Frame-Options value
referrerPolicystring"no-referrer"Referrer-Policy value
hstsboolean · { maxAge?, includeSubDomains?, preload? }falseStrict-Transport-Securitytrue = one year
permissionsPolicystring— (omitted)Permissions-Policy value
crossOriginOpenerPolicy"same-origin" · "same-origin-allow-popups" · "unsafe-none"— (omitted)Cross-Origin-Opener-Policy value
crossOriginResourcePolicy"same-origin" · "same-site" · "cross-origin"— (omitted)Cross-Origin-Resource-Policy value
crossOriginEmbedderPolicy"require-corp" · "credentialless"— (omitted)Cross-Origin-Embedder-Policy value
originAgentClusterbooleantrueOrigin-Agent-Cluster: ?1false omits
dnsPrefetchControlboolean · { allow: boolean }trueoffX-DNS-Prefetch-Control; false omits
downloadOptionsbooleantrueX-Download-Options: noopenfalse omits
permittedCrossDomainPolicies"none" · "master-only" · "by-content-type" · "all""none"X-Permitted-Cross-Domain-Policies value
poweredByboolean · stringtruetrue removes X-Powered-By, a string sets a decoy, false keeps the app's
xssProtectionbooleantrueX-XSS-Protection: 0false omits
overridebooleanfalseReplace values the app set explicitly
.plug(
  securityHeaders({
    contentSecurityPolicy: {
      directives: { scriptSrc: ["'self'", "https://cdn.example.com"] }, // merged over the defaults
      reportOnly: true, // Content-Security-Policy-Report-Only while you tune
    },
    hsts: { maxAge: 63072000, includeSubDomains: true },
    permissionsPolicy: "camera=(), microphone=()",
  }),
)

HSTS is off by default because it is sticky — once a browser sees it, it insists on HTTPS for the whole max-age. Enable it only on deployments that already serve HTTPS (never on plain-HTTP local dev). The same caution applies to upgrade-insecure-requests in the default CSP.

Runtime configuration

Header policy is exactly the config you want to flip without a redeploy — enable HSTS the day HTTPS lands, tighten the CSP after an audit. Pass a configSource() and options follow the database within one sync interval:

const headers = configSource({
  plugin: "security-headers",
  code: { hsts: false }, // safe floor for local dev
  db: { store: db },
  kv: cache,
});
on(every("30s"), headers.sync());
export const app = oke({ name: "shop", env: "dev" }).plug(securityHeaders(headers));
INSERT INTO security_headers_config ("key", "value")
VALUES ('config', '{"hsts": true}');

See Plugins → Runtime configuration for the full contract.

Notes

BehaviorDetail
Failures includedonResponse runs after onError — denials get the same headers
App winsA header set earlier (app hook, flow) is kept unless override: true
Non-HTTP triggersNo-op — nothing to stamp outside HTTP
ScopeFlow responses — infra routes (/_oke/*, 404s) bypass the pipeline

Next

On this page