shield

Turn on the security basics every API needs: CORS, CSRF protection, safe headers and rate limits.

BackendServer

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.