---
title: "Secure Headers and CORS"
description: "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 ..."
last_updated: "2026-10-12T08:14:12.743647+00:00"
canonical_url: "https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/security-middleware/secure-headers-and-cors"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [src/middleware/secure-headers/secure-headers.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts)
- [src/middleware/secure-headers/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/index.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/aws-lambda/handler.ts)
- [src/middleware/csrf/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/csrf/index.ts)
- [src/middleware/cache/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cache/index.ts)
- [src/middleware/jwk/jwk.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/jwk/jwk.ts)
- [src/helper/streaming/sse.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/streaming/sse.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/context.ts)
- [src/middleware/etag/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/etag/index.ts)
- [src/middleware/jwt/jwt.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/jwt/jwt.ts)
- [src/middleware/cors/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts)
- [src/middleware/bearer-auth/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/bearer-auth/index.ts)
- [src/middleware/language/language.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/language/language.ts)
- [src/middleware/secure-headers/permissions-policy.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/permissions-policy.ts)
- [src/middleware/ip-restriction/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/ip-restriction/index.ts)
- [src/utils/headers.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/utils/headers.ts)
- [package.json](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/package.json)
- [src/helper/cookie/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/cookie/index.ts)
- [src/helper/streaming/text.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/streaming/text.ts)
- [src/middleware/timing/timing.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/timing/timing.ts)
- [src/middleware/method-override/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/method-override/index.ts)
- [src/utils/cookie.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/utils/cookie.ts)
- [src/helper/proxy/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/proxy/index.ts)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/cloudflare-pages/handler.ts)
- [src/helper/ssg/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/ssg/index.ts)
- [src/helper/ssg/middleware.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/ssg/middleware.ts)
- [src/middleware/jwt/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/jwt/index.ts)
- [src/middleware/jwk/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/jwk/index.ts)
- [src/middleware/powered-by/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/powered-by/index.ts)
</details>

## 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L69-L145), [src/middleware/cors/index.ts:9-148](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts#L9-L148)

## 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/index.ts#L1-L8), [src/middleware/secure-headers/secure-headers.ts:6-145](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L6-L145)

### 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L94-L124)

> [!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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L131-L145)

## 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](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/traffic-middleware/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.

```typescript
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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L15-L44), [src/middleware/secure-headers/secure-headers.ts:131-145](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L131-L145)

> [!NOTE]
> Reusing the `NONCE` handler across multiple directives within the same [request lifecycle](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/core-engine/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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L137-L143)

### 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 | 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L18-L44)

## 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.

```typescript
type PermissionsPolicyValue = '*' | 'self' | 'src' | 'none' | string

type PermissionsPolicyOptions = Partial<
  Record<PermissionsPolicyDirective, PermissionsPolicyValue[] | boolean>
>
```

Sources: [src/middleware/secure-headers/secure-headers.ts:61-65](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L61-L65)

> [!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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L63-L65)

### Standardized, Proposed, and Experimental Features

The `PermissionsPolicyDirective` union type incorporates standardized specifications, proposed features still undergoing standardization, and experimental features available for developer testing. 

```typescript
export type PermissionsPolicyDirective =
  | StandardizedFeatures
  | ProposedFeatures
  | ExperimentalFeatures
```

Sources: [src/middleware/secure-headers/permissions-policy.ts:3-7](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/permissions-policy.ts#L3-L7)

| 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/permissions-policy.ts#L11-L86)

## 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L67-L79), [src/middleware/secure-headers/secure-headers.ts:99-100](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L99-L100), [src/middleware/secure-headers/secure-headers.ts:114-115](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L114-L115)

> [!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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L67-L67)

### 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.

```typescript
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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/secure-headers/secure-headers.ts#L46-L59)

## 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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts#L9-L35), [src/middleware/cors/index.ts:63-70](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts#L63-L70)

> [!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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts#L72-L84)

### 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`.

```typescript
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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts#L114-L148)

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](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/cors/index.ts#L114-L156)

## Related

- [CSRF and Body Limit](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/security-middleware/csrf-and-body-limit)
- [IP Restriction](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/security-middleware/ip-restriction)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/llms.txt) for all pages in this wiki.
