Skip to content

Security API

The @cloudwerk/security package provides comprehensive security middleware for Cloudwerk applications, including CSRF protection, security headers, Content Security Policy, origin validation, and client-side helpers.

Terminal window
pnpm add @cloudwerk/security

All-in-one middleware that composes multiple security protections.

import { securityMiddleware } from '@cloudwerk/security/middleware'
export const middleware = securityMiddleware(options)
PropertyTypeDefaultDescription
csrfCSRFMiddlewareOptions | falseEnabledCSRF protection config
requestedWithRequestedWithOptions | falseEnabledX-Requested-With validation
headersSecurityHeadersOptions | falseEnabledSecurity headers config
cspCSPOptions | falseDisabledContent Security Policy
originOriginValidationOptions | falseDisabledOrigin validation config
allowedOriginsstring[]-Shorthand for origin.allowedOrigins

Default behavior:

  • CSRF protection: Enabled
  • X-Requested-With: Enabled (forces CORS preflight)
  • Security headers: Enabled
  • CSP: Disabled (requires app-specific config)
  • Origin validation: Disabled (requires allowedOrigins config)

Examples:

// Use all defaults
export const middleware = securityMiddleware()
// Full configuration
export const middleware = securityMiddleware({
allowedOrigins: ['https://myapp.com'],
csrf: {
excludePaths: ['/api/webhooks/stripe'],
},
csp: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'https://cdn.example.com'],
},
reportOnly: true,
},
headers: {
frameOptions: 'SAMEORIGIN',
},
})
// Disable specific protections
export const middleware = securityMiddleware({
csrf: false,
requestedWith: false,
})

Create CSRF protection middleware using the double-submit cookie pattern.

import { csrfMiddleware } from '@cloudwerk/security/middleware'
export const middleware = csrfMiddleware(options)
PropertyTypeDefaultDescription
cookieNamestring'cloudwerk.csrf-token'CSRF cookie name
headerNamestring'X-CSRF-Token'CSRF header name
formFieldNamestring'csrf_token'Form field name
methodsstring[]['POST', 'PUT', 'PATCH', 'DELETE']Methods requiring validation
excludePathsstring[][]Paths to skip validation

Example:

export const middleware = csrfMiddleware({
excludePaths: ['/api/webhooks/stripe', '/api/webhooks/github'],
})

Generate a cryptographically secure CSRF token.

import { generateCsrfToken } from '@cloudwerk/security'
const token = generateCsrfToken()
// Returns: URL-safe base64 string (43 characters)

Set a CSRF cookie on a response.

import { generateCsrfToken, setCsrfCookie } from '@cloudwerk/security'
export function GET(request: Request) {
const token = generateCsrfToken()
const response = new Response(JSON.stringify({ csrfToken: token }))
return setCsrfCookie(response, token, options)
}
PropertyTypeDefaultDescription
cookieNamestring'cloudwerk.csrf-token'Cookie name
pathstring'/'Cookie path
httpOnlybooleanfalseMust be false for JS access
securebooleantrueHTTPS only
sameSite'strict' | 'lax' | 'none''lax'SameSite attribute
maxAgenumber86400Max age in seconds (24 hours)

Rotate the CSRF token after authentication state changes.

import { rotateCsrfToken } from '@cloudwerk/security'
// After successful login
export async function handleLogin(request: Request) {
const user = await validateCredentials(request)
const session = await createSession(user)
let response = createAuthResponse(user, session)
response = rotateCsrfToken(response)
return response
}

Verify a CSRF token using timing-safe comparison.

import { verifyCsrfToken } from '@cloudwerk/security'
const isValid = verifyCsrfToken(cookieToken, requestToken)
import {
getCsrfTokenFromCookie,
getCsrfTokenFromHeader,
getCsrfTokenFromFormBody,
} from '@cloudwerk/security'
// Get from cookie
const cookieToken = getCsrfTokenFromCookie(request)
// Get from header
const headerToken = getCsrfTokenFromHeader(request)
// Get from form body (async)
const formToken = await getCsrfTokenFromFormBody(request)

Set standard security headers on responses.

import { securityHeadersMiddleware } from '@cloudwerk/security/middleware'
export const middleware = securityHeadersMiddleware(options)
PropertyTypeDefaultDescription
contentTypeOptions'nosniff' | false'nosniff'X-Content-Type-Options
frameOptions'DENY' | 'SAMEORIGIN' | false'DENY'X-Frame-Options
referrerPolicyReferrerPolicy | false'strict-origin-when-cross-origin'Referrer-Policy
xssProtection'0' | '1' | '1; mode=block' | false'0'X-XSS-Protection
permittedCrossDomainPoliciesstring | false'none'X-Permitted-Cross-Domain-Policies
dnsPrefetchControl'on' | 'off' | false'off'X-DNS-Prefetch-Control
crossOriginOpenerPolicyCOOP | false-Cross-Origin-Opener-Policy
crossOriginEmbedderPolicyCOEP | false-Cross-Origin-Embedder-Policy
crossOriginResourcePolicyCORP | false-Cross-Origin-Resource-Policy

Referrer-Policy values: 'no-referrer', 'no-referrer-when-downgrade', 'origin', 'origin-when-cross-origin', 'same-origin', 'strict-origin', 'strict-origin-when-cross-origin', 'unsafe-url'

Example:

export const middleware = securityHeadersMiddleware({
frameOptions: 'SAMEORIGIN',
crossOriginOpenerPolicy: 'same-origin',
crossOriginEmbedderPolicy: 'require-corp',
})

Generate and set Content-Security-Policy headers.

import { cspMiddleware } from '@cloudwerk/security/middleware'
export const middleware = cspMiddleware(options)
PropertyTypeDefaultDescription
directivesCSPDirectives{}CSP directives
reportOnlybooleanfalseUse report-only mode
useNoncebooleanfalseGenerate nonces for inline scripts
nonceContextKeystring'cspNonce'Context key for nonce

Common directives:

DirectiveDescription
defaultSrcFallback for other fetch directives
scriptSrcValid sources for scripts
styleSrcValid sources for stylesheets
imgSrcValid sources for images
fontSrcValid sources for fonts
connectSrcValid sources for fetch, XMLHttpRequest, WebSocket
frameSrcValid sources for frames
frameAncestorsValid parents for embedding
formActionValid form submission targets
baseUriValid base URIs
reportUriURI to report violations to
upgradeInsecureRequestsUpgrade HTTP to HTTPS

Examples:

// Basic CSP
export const middleware = cspMiddleware({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'https://cdn.example.com'],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", 'data:', 'https:'],
connectSrc: ["'self'", 'https://api.example.com'],
},
})
// Report-only mode for testing
export const middleware = cspMiddleware({
directives: {
defaultSrc: ["'self'"],
reportUri: '/api/csp-report',
},
reportOnly: true,
})
// With nonce generation
export const middleware = cspMiddleware({
directives: {
scriptSrc: ["'self'"],
},
useNonce: true,
})
// Access nonce via response header: X-CSP-Nonce

Generate a CSP header string from directives.

import { generateCSPHeader } from '@cloudwerk/security'
const csp = generateCSPHeader({
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'https://cdn.example.com'],
})
// "default-src 'self'; script-src 'self' https://cdn.example.com"

Generate a cryptographic nonce for inline scripts.

import { generateNonce } from '@cloudwerk/security'
const nonce = generateNonce()
// Use in template: <script nonce={nonce}>...</script>

Validate Origin/Referer headers to prevent cross-origin attacks.

import { originValidationMiddleware } from '@cloudwerk/security/middleware'
export const middleware = originValidationMiddleware(options)
PropertyTypeDefaultDescription
allowedOriginsstring[][]Full origin URLs (e.g., 'https://example.com')
allowedHostsstring[][]Hostnames only (e.g., 'example.com')
allowSubdomainsbooleanfalseAllow subdomains of allowed hosts
methodsstring[]['POST', 'PUT', 'PATCH', 'DELETE']Methods requiring validation
excludePathsstring[][]Paths to skip validation
rejectMissingOriginbooleantrueReject requests without Origin header

Examples:

// Allow specific origins
export const middleware = originValidationMiddleware({
allowedOrigins: ['https://myapp.com', 'https://admin.myapp.com'],
})
// Allow all subdomains
export const middleware = originValidationMiddleware({
allowedHosts: ['myapp.com'],
allowSubdomains: true,
})
// Allows: myapp.com, www.myapp.com, api.myapp.com, etc.
// Exclude webhooks
export const middleware = originValidationMiddleware({
allowedOrigins: ['https://myapp.com'],
excludePaths: ['/api/webhooks'],
rejectMissingOrigin: false, // Allow webhooks without Origin
})

Require X-Requested-With header to force CORS preflight.

import { requestedWithMiddleware } from '@cloudwerk/security/middleware'
export const middleware = requestedWithMiddleware(options)
PropertyTypeDefaultDescription
requiredValuestring'XMLHttpRequest'Required header value
methodsstring[]['POST', 'PUT', 'PATCH', 'DELETE']Methods requiring validation
excludePathsstring[][]Paths to skip validation

Example:

export const middleware = requestedWithMiddleware({
excludePaths: ['/api/webhooks'],
})

The client module provides helpers for making secure fetch requests from the browser.

A fetch wrapper that automatically adds CSRF tokens and X-Requested-With headers.

import { secureFetch } from '@cloudwerk/security/client'
// POST request with automatic security headers
const response = await secureFetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' }),
})
// Works with FormData
const response = await secureFetch('/api/upload', {
method: 'POST',
body: formData,
})
// DELETE request
const response = await secureFetch(`/api/users/${userId}`, {
method: 'DELETE',
})

What secureFetch adds:

  • X-CSRF-Token header (read from cookie)
  • X-Requested-With: XMLHttpRequest header
  • credentials: 'same-origin' (by default)

Configure global defaults for secure fetch.

import { configureSecureFetch } from '@cloudwerk/security/client'
configureSecureFetch({
baseUrl: '/api',
credentials: 'include',
csrfCookieName: 'my-csrf-token',
csrfHeaderName: 'X-My-CSRF',
})
PropertyTypeDefaultDescription
csrfCookieNamestring'cloudwerk.csrf-token'CSRF cookie name
csrfHeaderNamestring'X-CSRF-Token'CSRF header name
requestedWithValuestring'XMLHttpRequest'X-Requested-With value
credentialsRequestCredentials'same-origin'Credentials mode
baseUrlstring-Base URL for relative paths
import {
secureGet,
securePost,
securePut,
securePatch,
secureDelete,
} from '@cloudwerk/security/client'
// GET (no CSRF/X-Requested-With needed for GET)
const response = await secureGet('/api/users')
// POST with auto JSON serialization
const response = await securePost('/api/users', { name: 'Alice' })
// PUT
const response = await securePut(`/api/users/${id}`, { name: 'Bob' })
// PATCH
const response = await securePatch(`/api/users/${id}`, { name: 'Carol' })
// DELETE
const response = await secureDelete(`/api/users/${id}`)

Get the CSRF token from cookies.

import { getCsrfToken } from '@cloudwerk/security/client'
const token = getCsrfToken()
// Use in custom fetch calls or forms

Add CSRF token to a headers object.

import { withCsrfToken } from '@cloudwerk/security/client'
const headers = withCsrfToken({
'Content-Type': 'application/json',
})
fetch('/api/users', {
method: 'POST',
headers,
body: JSON.stringify(data),
})

Generate a hidden input element with the CSRF token for forms.

import { csrfInput } from '@cloudwerk/security/client'
const formHtml = `
<form method="POST" action="/submit">
${csrfInput()}
<input type="text" name="email" />
<button type="submit">Submit</button>
</form>
`
// Outputs: <input type="hidden" name="csrf_token" value="..." />

CSRF protection has moved from @cloudwerk/auth to @cloudwerk/security. The old imports continue to work with a deprecation warning.

Before:

import { csrfMiddleware, generateCsrfToken } from '@cloudwerk/auth/middleware'

After:

import { csrfMiddleware, generateCsrfToken } from '@cloudwerk/security'
// or
import { csrfMiddleware, generateCsrfToken } from '@cloudwerk/security/middleware'