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.
Installation
Section titled “Installation”pnpm add @cloudwerk/securityCombined Security Middleware
Section titled “Combined Security Middleware”securityMiddleware()
Section titled “securityMiddleware()”All-in-one middleware that composes multiple security protections.
import { securityMiddleware } from '@cloudwerk/security/middleware'
export const middleware = securityMiddleware(options)SecurityMiddlewareOptions
Section titled “SecurityMiddlewareOptions”| Property | Type | Default | Description |
|---|---|---|---|
csrf | CSRFMiddlewareOptions | false | Enabled | CSRF protection config |
requestedWith | RequestedWithOptions | false | Enabled | X-Requested-With validation |
headers | SecurityHeadersOptions | false | Enabled | Security headers config |
csp | CSPOptions | false | Disabled | Content Security Policy |
origin | OriginValidationOptions | false | Disabled | Origin validation config |
allowedOrigins | string[] | - | 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 defaultsexport const middleware = securityMiddleware()
// Full configurationexport 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 protectionsexport const middleware = securityMiddleware({ csrf: false, requestedWith: false,})CSRF Protection
Section titled “CSRF Protection”csrfMiddleware()
Section titled “csrfMiddleware()”Create CSRF protection middleware using the double-submit cookie pattern.
import { csrfMiddleware } from '@cloudwerk/security/middleware'
export const middleware = csrfMiddleware(options)CSRFMiddlewareOptions
Section titled “CSRFMiddlewareOptions”| Property | Type | Default | Description |
|---|---|---|---|
cookieName | string | 'cloudwerk.csrf-token' | CSRF cookie name |
headerName | string | 'X-CSRF-Token' | CSRF header name |
formFieldName | string | 'csrf_token' | Form field name |
methods | string[] | ['POST', 'PUT', 'PATCH', 'DELETE'] | Methods requiring validation |
excludePaths | string[] | [] | Paths to skip validation |
Example:
export const middleware = csrfMiddleware({ excludePaths: ['/api/webhooks/stripe', '/api/webhooks/github'],})generateCsrfToken()
Section titled “generateCsrfToken()”Generate a cryptographically secure CSRF token.
import { generateCsrfToken } from '@cloudwerk/security'
const token = generateCsrfToken()// Returns: URL-safe base64 string (43 characters)setCsrfCookie()
Section titled “setCsrfCookie()”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)}SetCsrfCookieOptions
Section titled “SetCsrfCookieOptions”| Property | Type | Default | Description |
|---|---|---|---|
cookieName | string | 'cloudwerk.csrf-token' | Cookie name |
path | string | '/' | Cookie path |
httpOnly | boolean | false | Must be false for JS access |
secure | boolean | true | HTTPS only |
sameSite | 'strict' | 'lax' | 'none' | 'lax' | SameSite attribute |
maxAge | number | 86400 | Max age in seconds (24 hours) |
rotateCsrfToken()
Section titled “rotateCsrfToken()”Rotate the CSRF token after authentication state changes.
import { rotateCsrfToken } from '@cloudwerk/security'
// After successful loginexport 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}verifyCsrfToken()
Section titled “verifyCsrfToken()”Verify a CSRF token using timing-safe comparison.
import { verifyCsrfToken } from '@cloudwerk/security'
const isValid = verifyCsrfToken(cookieToken, requestToken)Token Extraction Helpers
Section titled “Token Extraction Helpers”import { getCsrfTokenFromCookie, getCsrfTokenFromHeader, getCsrfTokenFromFormBody,} from '@cloudwerk/security'
// Get from cookieconst cookieToken = getCsrfTokenFromCookie(request)
// Get from headerconst headerToken = getCsrfTokenFromHeader(request)
// Get from form body (async)const formToken = await getCsrfTokenFromFormBody(request)Security Headers
Section titled “Security Headers”securityHeadersMiddleware()
Section titled “securityHeadersMiddleware()”Set standard security headers on responses.
import { securityHeadersMiddleware } from '@cloudwerk/security/middleware'
export const middleware = securityHeadersMiddleware(options)SecurityHeadersOptions
Section titled “SecurityHeadersOptions”| Property | Type | Default | Description |
|---|---|---|---|
contentTypeOptions | 'nosniff' | false | 'nosniff' | X-Content-Type-Options |
frameOptions | 'DENY' | 'SAMEORIGIN' | false | 'DENY' | X-Frame-Options |
referrerPolicy | ReferrerPolicy | false | 'strict-origin-when-cross-origin' | Referrer-Policy |
xssProtection | '0' | '1' | '1; mode=block' | false | '0' | X-XSS-Protection |
permittedCrossDomainPolicies | string | false | 'none' | X-Permitted-Cross-Domain-Policies |
dnsPrefetchControl | 'on' | 'off' | false | 'off' | X-DNS-Prefetch-Control |
crossOriginOpenerPolicy | COOP | false | - | Cross-Origin-Opener-Policy |
crossOriginEmbedderPolicy | COEP | false | - | Cross-Origin-Embedder-Policy |
crossOriginResourcePolicy | CORP | 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',})Content Security Policy
Section titled “Content Security Policy”cspMiddleware()
Section titled “cspMiddleware()”Generate and set Content-Security-Policy headers.
import { cspMiddleware } from '@cloudwerk/security/middleware'
export const middleware = cspMiddleware(options)CSPOptions
Section titled “CSPOptions”| Property | Type | Default | Description |
|---|---|---|---|
directives | CSPDirectives | {} | CSP directives |
reportOnly | boolean | false | Use report-only mode |
useNonce | boolean | false | Generate nonces for inline scripts |
nonceContextKey | string | 'cspNonce' | Context key for nonce |
CSPDirectives
Section titled “CSPDirectives”Common directives:
| Directive | Description |
|---|---|
defaultSrc | Fallback for other fetch directives |
scriptSrc | Valid sources for scripts |
styleSrc | Valid sources for stylesheets |
imgSrc | Valid sources for images |
fontSrc | Valid sources for fonts |
connectSrc | Valid sources for fetch, XMLHttpRequest, WebSocket |
frameSrc | Valid sources for frames |
frameAncestors | Valid parents for embedding |
formAction | Valid form submission targets |
baseUri | Valid base URIs |
reportUri | URI to report violations to |
upgradeInsecureRequests | Upgrade HTTP to HTTPS |
Examples:
// Basic CSPexport 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 testingexport const middleware = cspMiddleware({ directives: { defaultSrc: ["'self'"], reportUri: '/api/csp-report', }, reportOnly: true,})
// With nonce generationexport const middleware = cspMiddleware({ directives: { scriptSrc: ["'self'"], }, useNonce: true,})// Access nonce via response header: X-CSP-NoncegenerateCSPHeader()
Section titled “generateCSPHeader()”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"generateNonce()
Section titled “generateNonce()”Generate a cryptographic nonce for inline scripts.
import { generateNonce } from '@cloudwerk/security'
const nonce = generateNonce()// Use in template: <script nonce={nonce}>...</script>Origin Validation
Section titled “Origin Validation”originValidationMiddleware()
Section titled “originValidationMiddleware()”Validate Origin/Referer headers to prevent cross-origin attacks.
import { originValidationMiddleware } from '@cloudwerk/security/middleware'
export const middleware = originValidationMiddleware(options)OriginValidationOptions
Section titled “OriginValidationOptions”| Property | Type | Default | Description |
|---|---|---|---|
allowedOrigins | string[] | [] | Full origin URLs (e.g., 'https://example.com') |
allowedHosts | string[] | [] | Hostnames only (e.g., 'example.com') |
allowSubdomains | boolean | false | Allow subdomains of allowed hosts |
methods | string[] | ['POST', 'PUT', 'PATCH', 'DELETE'] | Methods requiring validation |
excludePaths | string[] | [] | Paths to skip validation |
rejectMissingOrigin | boolean | true | Reject requests without Origin header |
Examples:
// Allow specific originsexport const middleware = originValidationMiddleware({ allowedOrigins: ['https://myapp.com', 'https://admin.myapp.com'],})
// Allow all subdomainsexport const middleware = originValidationMiddleware({ allowedHosts: ['myapp.com'], allowSubdomains: true,})// Allows: myapp.com, www.myapp.com, api.myapp.com, etc.
// Exclude webhooksexport const middleware = originValidationMiddleware({ allowedOrigins: ['https://myapp.com'], excludePaths: ['/api/webhooks'], rejectMissingOrigin: false, // Allow webhooks without Origin})X-Requested-With Validation
Section titled “X-Requested-With Validation”requestedWithMiddleware()
Section titled “requestedWithMiddleware()”Require X-Requested-With header to force CORS preflight.
import { requestedWithMiddleware } from '@cloudwerk/security/middleware'
export const middleware = requestedWithMiddleware(options)RequestedWithOptions
Section titled “RequestedWithOptions”| Property | Type | Default | Description |
|---|---|---|---|
requiredValue | string | 'XMLHttpRequest' | Required header value |
methods | string[] | ['POST', 'PUT', 'PATCH', 'DELETE'] | Methods requiring validation |
excludePaths | string[] | [] | Paths to skip validation |
Example:
export const middleware = requestedWithMiddleware({ excludePaths: ['/api/webhooks'],})Client API
Section titled “Client API”The client module provides helpers for making secure fetch requests from the browser.
secureFetch()
Section titled “secureFetch()”A fetch wrapper that automatically adds CSRF tokens and X-Requested-With headers.
import { secureFetch } from '@cloudwerk/security/client'
// POST request with automatic security headersconst response = await secureFetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Alice' }),})
// Works with FormDataconst response = await secureFetch('/api/upload', { method: 'POST', body: formData,})
// DELETE requestconst response = await secureFetch(`/api/users/${userId}`, { method: 'DELETE',})What secureFetch adds:
X-CSRF-Tokenheader (read from cookie)X-Requested-With: XMLHttpRequestheadercredentials: 'same-origin'(by default)
configureSecureFetch()
Section titled “configureSecureFetch()”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',})SecureFetchOptions
Section titled “SecureFetchOptions”| Property | Type | Default | Description |
|---|---|---|---|
csrfCookieName | string | 'cloudwerk.csrf-token' | CSRF cookie name |
csrfHeaderName | string | 'X-CSRF-Token' | CSRF header name |
requestedWithValue | string | 'XMLHttpRequest' | X-Requested-With value |
credentials | RequestCredentials | 'same-origin' | Credentials mode |
baseUrl | string | - | Base URL for relative paths |
Convenience Methods
Section titled “Convenience Methods”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 serializationconst response = await securePost('/api/users', { name: 'Alice' })
// PUTconst response = await securePut(`/api/users/${id}`, { name: 'Bob' })
// PATCHconst response = await securePatch(`/api/users/${id}`, { name: 'Carol' })
// DELETEconst response = await secureDelete(`/api/users/${id}`)getCsrfToken()
Section titled “getCsrfToken()”Get the CSRF token from cookies.
import { getCsrfToken } from '@cloudwerk/security/client'
const token = getCsrfToken()// Use in custom fetch calls or formswithCsrfToken()
Section titled “withCsrfToken()”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),})csrfInput()
Section titled “csrfInput()”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="..." />Migration from @cloudwerk/auth
Section titled “Migration from @cloudwerk/auth”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'// orimport { csrfMiddleware, generateCsrfToken } from '@cloudwerk/security/middleware'Next Steps
Section titled “Next Steps”- Security Guide - Best practices and patterns
- Authentication Guide - Auth with security middleware
- Auth API - Authentication system reference