# CSRF Protection
This middleware protects against CSRF attacks by checking both the `Origin` header and the `Sec-Fetch-Site` header. The request is allowed if either validation passes.
The middleware only validates requests that:
- Use unsafe HTTP methods (not GET, HEAD, or OPTIONS)
- Have content types that can be sent by HTML forms (`application/x-www-form-urlencoded`, `multipart/form-data`, or `text/plain`)
Old browsers that do not send `Origin` headers, or environments that use reverse proxies to remove these headers, may not work well. In such environments, use other CSRF token methods.
## Import
```ts
import { Hono } from 'hono'
import { csrf } from 'hono/csrf'
```
## Usage
```ts
const app = new Hono()
// Default: both origin and sec-fetch-site validation
app.use(csrf())
// Allow specific origins
app.use(csrf({ origin: 'https://myapp.example.com' }))
// Allow multiple origins
app.use(
csrf({
origin: [
'https://myapp.example.com',
'https://development.myapp.example.com',
],
})
)
// Allow specific sec-fetch-site values
app.use(csrf({ secFetchSite: 'same-origin' }))
app.use(csrf({ secFetchSite: ['same-origin', 'none'] }))
// Dynamic origin validation
// It is strongly recommended that the protocol be verified to ensure a match to `$`.
// You should *never* do a forward match.
app.use(
'*',
csrf({
origin: (origin) =>
/https:\/\/(\w+\.)?myapp\.example\.com$/.test(origin),
})
)
// Dynamic sec-fetch-site validation
app.use(
csrf({
secFetchSite: (secFetchSite, c) => {
// Always allow same-origin
if (secFetchSite === 'same-origin') return true
// Allow cross-site for webhook endpoints
if (
secFetchSite === 'cross-site' &&
c.req.path.startsWith('/webhook/')
) {
return true
}
return false
},
})
)
```
## Options
### origin: `string` | `string[]` | `Function`
Specify allowed origins for CSRF protection.
- **`string`**: Single allowed origin (e.g., `'https://example.com'`)
- **`string[]`**: Array of allowed origins
- **`Function`**: Custom handler `(origin: string, context: Context) => boolean` for flexible origin validation and bypass logic
**Default**: Only same origin as the request URL
The function handler receives the request's `Origin` header value and the request context, allowing for dynamic validation based on request properties like path, headers, or other context data.
### secFetchSite: `string` | `string[]` | `Function`
Specify allowed Sec-Fetch-Site header values for CSRF protection using [Fetch Metadata](https://web.dev/articles/fetch-metadata).
- **`string`**: Single allowed value (e.g., `'same-origin'`)
- **`string[]`**: Array of allowed values (e.g., `['same-origin', 'none']`)
- **`Function`**: Custom handler `(secFetchSite: string, context: Context) => boolean` for flexible validation
**Default**: Only allows `'same-origin'`
Standard Sec-Fetch-Site values:
- `same-origin`: Request from same origin
- `same-site`: Request from same site (different subdomain)
- `cross-site`: Request from different site
- `none`: Request not from a web page (e.g., browser address bar, bookmark)
The function handler receives the request's `Sec-Fetch-Site` header value and the request context, enabling dynamic validation based on request properties.