shield
Turn on the security basics every API needs: CORS, CSRF protection, safe headers and rate limits.
Every export of kitr/shield, kitr/shield/provider, read from the published type definitions. The guide shows them in use.
kitr/shield
cors
function cors(options?: CorsOptions): Middleware;
CORS with preflight answers.
createMemoryRateLimitStore
function createMemoryRateLimitStore(): RateLimitStore;
csrf
function csrf(options?: CsrfOptions): Middleware;
Double-submit cookie CSRF: a readable cookie carries a token the browser must echo in a header
(fetch from another origin cannot read the cookie, so it cannot forge the header). kitr/http
sends the header automatically.
rateLimit
function rateLimit(options?: RateLimitOptions): Middleware;
Fixed-window rate limit with RateLimit-* headers and a 429 when exceeded.
securityHeaders
function securityHeaders(options?: HeadersOptions): Middleware;
Security headers on every response.
shield
function shield<S extends {
use(middleware: Middleware): unknown;
app?: {
config: any;
};
}>(server: S, config?: ShieldConfig): S;
Attach the shield to a kitr server (or any object with use(middleware)), reading config/shield.ts.
shieldMiddlewares
function shieldMiddlewares(config?: ShieldConfig): Middleware[];
The middlewares config/shield.ts asks for, in the right order.
DEFAULT_CSP
const DEFAULT_CSP = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'";
defineConfig
const defineConfig: <const C extends ShieldConfig>(config: C) => C;
CorsOptions
interface CorsOptions {
/** `'*'`, a list of origins, or a predicate. Default: same-origin only (no header). */
origin?: '*' | string[] | ((origin: string) => boolean);
methods?: string[];
headers?: string[];
credentials?: boolean;
/** Seconds a preflight answer may be cached. Default 600. */
maxAge?: number;
}
CsrfOptions
interface CsrfOptions {
/** Cookie that carries the token. Default `kitr-csrf`. */
cookie?: string;
/** Header the client sends it back in. Default `x-csrf-token`. */
header?: string;
/** Methods that need a token. Default: everything but GET, HEAD, OPTIONS. */
methods?: string[];
/** Paths that never need a token (webhooks). Prefix match. */
ignore?: string[];
secure?: boolean;
}
HeadersOptions
interface HeadersOptions {
/** `Content-Security-Policy`. A string, or false to leave it out. Default: a strict policy for an SPA/SSR app. */
contentSecurityPolicy?: string | false;
/** `Strict-Transport-Security` max-age in seconds; false to leave it out. Default one year in production. */
hsts?: number | false;
frameOptions?: 'DENY' | 'SAMEORIGIN' | false;
referrerPolicy?: string | false;
/** `Permissions-Policy`. Default disables camera, microphone and geolocation unless `native` asks for them. */
permissionsPolicy?: string | false;
}
RateLimitOptions
interface RateLimitOptions {
/** Window length in milliseconds. Default 60 000. */
windowMs?: number;
/** Requests per key per window. Default 100. */
max?: number;
/** Key a request. Default: the client IP. */
key?: (event: H3Event) => string;
/** Where counters live. Default: this process. */
store?: RateLimitStore;
/** Paths that are never limited. Prefix match. */
ignore?: string[];
}
RateLimitStore
interface RateLimitStore {
/** Increment and return the count and when the window resets (ms epoch). */
hit(key: string, windowMs: number): Promise<{
count: number;
resetAt: number;
}>;
}
ShieldConfig
interface ShieldConfig {
/** false turns the headers off. */
headers?: HeadersOptions | false;
cors?: CorsOptions | false;
csrf?: CsrfOptions | false;
rateLimit?: RateLimitOptions | false;
}
kitr/shield/provider
shieldProvider
const shieldProvider: import("@kitr/core").KitrProvider;
Validates config/shield.ts at boot; shield(server) in server/main.ts attaches the middleware.