Relevant source files
The following files were used as context for generating this wiki page:
- src/middleware/secure-headers/secure-headers.ts
- src/middleware/secure-headers/index.ts
- src/adapter/aws-lambda/handler.ts
- src/middleware/csrf/index.ts
- src/middleware/cache/index.ts
- src/middleware/jwk/jwk.ts
- src/helper/streaming/sse.ts
- src/context.ts
- src/middleware/etag/index.ts
- src/middleware/jwt/jwt.ts
- src/middleware/cors/index.ts
- src/middleware/bearer-auth/index.ts
- src/middleware/language/language.ts
- src/middleware/secure-headers/permissions-policy.ts
- src/middleware/ip-restriction/index.ts
- src/utils/headers.ts
- package.json
- src/helper/cookie/index.ts
- src/helper/streaming/text.ts
- src/middleware/timing/timing.ts
- src/middleware/method-override/index.ts
- src/utils/cookie.ts
- src/helper/proxy/index.ts
- src/adapter/cloudflare-pages/handler.ts
- src/helper/ssg/index.ts
- src/helper/ssg/middleware.ts
- src/middleware/jwt/index.ts
- src/middleware/jwk/index.ts
- src/middleware/powered-by/index.ts
Overview
Hono provides robust middleware components for enforcing web security policies and managing cross-origin resource sharing. The secureHeaders middleware injects foundational defense headers such as X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, and dynamic Content Security Policy rules complete with cryptographic nonce generation. Complementing this, the cors middleware handles complex browser preflight requests, origin validation, and credentials configuration to safely permit cross-origin access.
Sources: src/middleware/secure-headers/secure-headers.ts:69-145, src/middleware/cors/index.ts:9-148
Secure Headers Middleware Architecture
Public Entry Points and Types
The secure headers middleware exports public entry points and type definitions via src/middleware/secure-headers/index.ts and src/middleware/secure-headers/secure-headers.ts. It exposes the secureHeaders middleware handler function, the NONCE content security policy handler constant, ContentSecurityPolicyOptionHandler, and SecureHeadersVariables which augment Hono's ContextVariableMap with secureHeadersNonce.
Sources: src/middleware/secure-headers/index.ts:1-8, src/middleware/secure-headers/secure-headers.ts:6-145
Default Header Mappings and Configuration Lifecycle
The middleware maintains a static mapping of header identifiers to default header names and fallback directive values through HEADERS_MAP and establishes baseline options via DEFAULT_OPTIONS. Each policy header can be toggled via boolean configuration or overridden with custom string values.
| Option Key | HTTP Header Name | Default Value / State |
|---|---|---|
crossOriginEmbedderPolicy | Cross-Origin-Embedder-Policy | require-corp (Disabled by default: false) |
crossOriginResourcePolicy | Cross-Origin-Resource-Policy | same-origin (Enabled: true) |
crossOriginOpenerPolicy | Cross-Origin-Opener-Policy | same-origin (Enabled: true) |
originAgentCluster | Origin-Agent-Cluster | ?1 (Enabled: true) |
referrerPolicy | Referrer-Policy | no-referrer (Enabled: true) |
strictTransportSecurity | Strict-Transport-Security | max-age=15552000; includeSubDomains (Enabled: true) |
xContentTypeOptions | X-Content-Type-Options | nosniff (Enabled: true) |
xDnsPrefetchControl | X-DNS-Prefetch-Control | off (Enabled: true) |
xDownloadOptions | X-Download-Options | noopen (Enabled: true) |
xFrameOptions | X-Frame-Options | SAMEORIGIN (Enabled: true) |
xPermittedCrossDomainPolicies | X-Permitted-Cross-Domain-Policies | none (Enabled: true) |
xXssProtection | X-XSS-Protection | 0 (Enabled: true) |
Sources: src/middleware/secure-headers/secure-headers.ts:94-124
Note
The secureHeadersNonce variable checks the current context state for an existing cryptographic nonce before executing generateNonce(), utilizing crypto.getRandomValues() on a 16-byte Uint8Array combined with encodeBase64().
Sources: src/middleware/secure-headers/secure-headers.ts:131-145
Content Security Policy Configuration
CSP Options and Dynamic Nonce Generation
The secureHeaders middleware supports configuring contentSecurityPolicy and contentSecurityPolicyReportOnly options via ContentSecurityPolicyOptions. Each directive accepts an array of string values or ContentSecurityPolicyOptionHandler callbacks. The built-in NONCE handler checks context storage for an existing secureHeadersNonce variable; if absent, it allocates a 16-byte Uint8Array, populates it using crypto.getRandomValues(), encodes the buffer into base64 via encodeBase64(), stores it in the context, and returns the formatted 'nonce-<nonce>' string.
export const NONCE: ContentSecurityPolicyOptionHandler = (ctx) => {
const key = 'secureHeadersNonce'
const init = ctx.get(key)
const nonce = init || generateNonce()
if (init == null) {
ctx.set(key, nonce)
}
return `'nonce-${nonce}'`
}Sources: src/middleware/secure-headers/secure-headers.ts:15-44, src/middleware/secure-headers/secure-headers.ts:131-145
Note
Reusing the NONCE handler across multiple directives within the same request lifecycle retrieves the cached nonce from the context rather than generating a new random buffer for each directive.
Sources: src/middleware/secure-headers/secure-headers.ts:137-143
Supported Content Security Policy Directives
| Option Property | Directive Name / Purpose | Value Type |
|---|---|---|
defaultSrc | default-src fallback fetch directive | ContentSecurityPolicyOptionValue |
baseUri | base-uri restriction for <base> elements | ContentSecurityPolicyOptionValue |
childSrc | child-src for web workers and nested browsing contexts | ContentSecurityPolicyOptionValue |
connectSrc | connect-src targets for fetch, XHR, and WebSockets | ContentSecurityPolicyOptionValue |
fontSrc | font-src valid sources for loading fonts | ContentSecurityPolicyOptionValue |
formAction | form-action valid endpoints for form submissions | ContentSecurityPolicyOptionValue |
frameAncestors | frame-ancestors embedding restriction for frames | ContentSecurityPolicyOptionValue |
frameSrc | frame-src sources for nested browsing contexts | ContentSecurityPolicyOptionValue |
imgSrc | img-src valid sources for images | ContentSecurityPolicyOptionValue |
manifestSrc | manifest-src sources for application manifests | ContentSecurityPolicyOptionValue |
mediaSrc | media-src sources for audio and video elements | ContentSecurityPolicyOptionValue |
objectSrc | object-src sources for <object>, <embed>, and <applet> | ContentSecurityPolicyOptionValue |
reportTo | report-to group destination identifier | string |
reportUri | report-uri endpoint URL or array of URLs | `string |
sandbox | sandbox applied sandbox restrictions | ContentSecurityPolicyOptionValue |
scriptSrc | script-src valid sources for JavaScript | ContentSecurityPolicyOptionValue |
scriptSrcAttr | script-src-attr valid sources for inline script event handlers | ContentSecurityPolicyOptionValue |
scriptSrcElem | script-src-elem valid sources for script elements | ContentSecurityPolicyOptionValue |
styleSrc | style-src valid sources for stylesheets | ContentSecurityPolicyOptionValue |
styleSrcAttr | style-src-attr valid sources for inline style attributes | ContentSecurityPolicyOptionValue |
styleSrcElem | style-src-elem valid sources for style elements | ContentSecurityPolicyOptionValue |
upgradeInsecureRequests | upgrade-insecure-requests flag directive | ContentSecurityPolicyOptionValue |
workerSrc | worker-src valid sources for worker scripts | ContentSecurityPolicyOptionValue |
requireTrustedTypesFor | require-trusted-types-for policy enforcement | ContentSecurityPolicyOptionValue |
trustedTypes | trusted-types policy names | ContentSecurityPolicyOptionValue |
Sources: src/middleware/secure-headers/secure-headers.ts:18-44
Permissions Policy Directives
Directive Mappings and Allowlist Formatting
The permissions-policy configuration handles W3C feature controls through PermissionsPolicyOptions, mapping directive keys to either an array of allowed origin strings or a boolean flag. The allowlist accepts standard keyword identifiers including '*', 'self', 'src', and 'none', or custom origin strings.
type PermissionsPolicyValue = '*' | 'self' | 'src' | 'none' | string
type PermissionsPolicyOptions = Partial<
Record<PermissionsPolicyDirective, PermissionsPolicyValue[] | boolean>
>Sources: src/middleware/secure-headers/secure-headers.ts:61-65
Note
Setting a permissions policy directive to true compiles to the allowlist keyword 'self', while false restricts the feature completely via 'none'.
Sources: src/middleware/secure-headers/secure-headers.ts:63-65
Standardized, Proposed, and Experimental Features
The PermissionsPolicyDirective union type incorporates standardized specifications, proposed features still undergoing standardization, and experimental features available for developer testing.
export type PermissionsPolicyDirective =
| StandardizedFeatures
| ProposedFeatures
| ExperimentalFeaturesSources: src/middleware/secure-headers/permissions-policy.ts:3-7
| Feature Category | Directive Identifiers |
|---|---|
| Standardized Features | accelerometer, ambientLightSensor, attributionReporting, autoplay, battery, bluetooth, camera, chUa, chUaArch, chUaBitness, chUaFullVersion, chUaFullVersionList, chUaMobile, chUaModel, chUaPlatform, chUaPlatformVersion, chUaWow64, computePressure, crossOriginIsolated, directSockets, displayCapture, encryptedMedia, executionWhileNotRendered, executionWhileOutOfViewport, fullscreen, geolocation, gyroscope, hid, identityCredentialsGet, idleDetection, keyboardMap, magnetometer, microphone, midi, navigationOverride, payment, pictureInPicture, publickeyCredentialsGet, screenWakeLock, serial, storageAccess, syncXhr, usb, webShare, windowManagement, xrSpatialTracking |
| Proposed Features | clipboardRead, clipboardWrite, gamepad, sharedAutofill, speakerSelection |
| Experimental Features | allScreensCapture, browsingTopics, capturedSurfaceControl, conversionMeasurement, digitalCredentialsGet, focusWithoutUserActivation, joinAdInterestGroup, localFonts, runAdAuction, smartCard, syncScript, trustTokenRedemption, unload, verticalScroll |
Sources: src/middleware/secure-headers/permissions-policy.ts:11-86
Reporting Endpoints and Transport Security
Transport Security and Referrer Protection
The secure headers middleware manages transport encryption enforcement and information leakage prevention through dedicated configuration options. Strict-Transport-Security (HSTS) and Referrer-Policy headers leverage overridable header definitions that accept either boolean flags or explicit custom strings. When enabled via default options, HSTS defaults to a max-age of 15,552,000 seconds with subdomain inclusion, while referrer policy restricts leakage via no-referrer.
| Option Name | Default Header Value | Type | Purpose |
|---|---|---|---|
strictTransportSecurity | Strict-Transport-Security: max-age=15552000; includeSubDomains | overridableHeader | Enforces secure HTTPS connections and subdomain protection |
referrerPolicy | Referrer-Policy: no-referrer | overridableHeader | Controls how referrer information is included with requests |
Sources: src/middleware/secure-headers/secure-headers.ts:67-79, src/middleware/secure-headers/secure-headers.ts:99-100, src/middleware/secure-headers/secure-headers.ts:114-115
Note
An overridableHeader type resolves as either a boolean toggle controlling default behavior or an explicit string value overriding the header completely.
Sources: src/middleware/secure-headers/secure-headers.ts:67-67
Report-To and Reporting-Endpoints Configuration
The middleware supports modern browser error reporting and diagnostic infrastructure through ReportToOptions and ReportingEndpointOptions interfaces. These options configure destination groups and endpoint URLs for reporting API violations, CSP breaches, and deprecation warnings.
interface ReportToOptions {
group: string
max_age: number
endpoints: ReportToEndpoint[]
}
interface ReportToEndpoint {
url: string
}
interface ReportingEndpointOptions {
name: string
url: string
}Sources: src/middleware/secure-headers/secure-headers.ts:46-59
Cross Origin Resource Sharing Architecture
CORS Options and Initialization
The CORS middleware entry point cors() accepts a configuration object defining origin, allowMethods, allowHeaders, maxAge, credentials, and exposeHeaders. When omitted, default options initialize origin to *, allowMethods to ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'], while allowHeaders and exposeHeaders default to empty arrays.
| Option Name | Default Value | Type | Purpose |
|---|---|---|---|
origin | * | string | string[] | ((origin: string, c: Context) => Promise<string | undefined | null> | string | undefined | null) | Sets Access-Control-Allow-Origin |
allowMethods | ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH'] | string[] | ((origin: string, c: Context) => Promise<string[]> | string[]) | Sets Access-Control-Allow-Methods |
allowHeaders | [] | string[] | Sets Access-Control-Allow-Headers |
maxAge | undefined | number | Sets Access-Control-Max-Age |
credentials | undefined | boolean | Sets Access-Control-Allow-Credentials |
exposeHeaders | [] | string[] | Sets Access-Control-Expose-Headers |
Sources: src/middleware/cors/index.ts:9-35, src/middleware/cors/index.ts:63-70
Note
The origin resolver handles three input types: wildcard strings (*), literal matching strings, arrays of allowed origins, and custom async or sync callback functions.
Sources: src/middleware/cors/index.ts:72-84
Preflight and Response Header Execution
During a request execution lifecycle, the middleware extracts the incoming Origin header and queries findAllowOrigin. If an allowed origin is returned, it sets Access-Control-Allow-Origin. When credentials is enabled, Access-Control-Allow-Credentials is set to true. If exposeHeaders contains items, they are joined by commas and assigned to Access-Control-Expose-Headers.
if (c.req.method === 'OPTIONS') {
if (opts.origin !== '*') {
set('Vary', 'Origin')
}
if (opts.maxAge != null) {
set('Access-Control-Max-Age', opts.maxAge.toString())
}
const allowMethods = await findAllowMethods(c.req.header('origin') || '', c)
if (allowMethods.length) {
set('Access-Control-Allow-Methods', allowMethods.join(','))
}
let headers = opts.allowHeaders
if (!headers?.length) {
const requestHeaders = c.req.header('Access-Control-Request-Headers')
if (requestHeaders) {
headers = requestHeaders.split(/\s*,\s*/)
}
}
if (headers?.length) {
set('Access-Control-Allow-Headers', headers.join(','))
c.res.headers.append('Vary', 'Access-Control-Request-Headers')
}
c.res.headers.delete('Content-Length')
c.res.headers.delete('Content-Type')
return new Response(null, {
headers: c.res.headers,
status: 204,
statusText: 'No Content',
})
}Sources: src/middleware/cors/index.ts:114-148
For OPTIONS preflight requests, the middleware appends Vary: Origin if origin is not *, populates Access-Control-Max-Age if maxAge is defined, and resolves allowed methods via findAllowMethods. If allowHeaders is empty, it falls back to parsing the Access-Control-Request-Headers request header. Finally, it deletes Content-Length and Content-Type headers and returns an HTTP 204 No Content response with the assembled headers. For standard requests, it invokes next() and appends Vary: Origin post-invocation if the origin option is restrictive.
Sources: src/middleware/cors/index.ts:114-156
Related
On This Page
OverviewSecure Headers Middleware ArchitecturePublic Entry Points and TypesDefault Header Mappings and Configuration LifecycleContent Security Policy ConfigurationCSP Options and Dynamic Nonce GenerationSupported Content Security Policy DirectivesPermissions Policy DirectivesDirective Mappings and Allowlist FormattingStandardized, Proposed, and Experimental FeaturesReporting Endpoints and Transport SecurityTransport Security and Referrer ProtectionReport-To and Reporting-Endpoints ConfigurationCross Origin Resource Sharing ArchitectureCORS Options and InitializationPreflight and Response Header ExecutionRelated