Skip to content

Security Middleware

OneBun provides three built-in security middleware components that can be enabled via ApplicationOptions shorthand properties or applied manually via the middleware array.

Quick Setup

typescript
import { OneBunApplication } from '@onebun/core';
import { AppModule } from './app.module';

const app = new OneBunApplication(AppModule, {
  cors: { origin: 'https://my-frontend.example.com', credentials: true },
  rateLimit: { windowMs: 60_000, max: 100 },
  security: true,  // use all defaults
});

await app.start();

Auto-ordering when all three are active:

Request → CorsMiddleware → RateLimitMiddleware → [your middleware] → SecurityHeadersMiddleware → Handler

CorsMiddleware

Handles preflight OPTIONS requests and adds Access-Control-* headers to all responses.

Via ApplicationOptions.cors

typescript
const app = new OneBunApplication(AppModule, {
  cors: {
    origin: 'https://my-frontend.example.com',
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE'],
    allowedHeaders: ['Content-Type', 'Authorization', 'X-API-Key'],
    exposedHeaders: ['X-Request-Id'],
    maxAge: 3600,
  },
});

Pass cors: true to allow all origins with default settings.

Via middleware array (manual configuration)

typescript
import { CorsMiddleware } from '@onebun/core';

const app = new OneBunApplication(AppModule, {
  middleware: [
    CorsMiddleware.configure({
      origin: /\.example\.com$/,  // RegExp origin matching
    }),
  ],
});

CorsOptions

PropertyTypeDefaultDescription
originstring | RegExp | Array<...> | ((origin) => boolean)'*'Allowed origin(s)
methodsstring[]['GET','HEAD','PUT','PATCH','POST','DELETE','OPTIONS']Allowed methods
allowedHeadersstring[]['Content-Type', 'Authorization']Allowed request headers
exposedHeadersstring[]Headers exposed to the browser
credentialsbooleanfalseAllow cookies / credentials
maxAgenumber86400Preflight cache duration (seconds)
preflightContinuebooleanfalsePass OPTIONS to next handler

Origin variants

typescript
// Any origin (default)
cors: true

// Exact string
cors: { origin: 'https://example.com' }

// RegExp
cors: { origin: /\.example\.com$/ }

// Array
cors: { origin: ['https://app1.com', 'https://app2.com', /\.dev$/] }

// Function predicate
cors: { origin: (o) => o.startsWith('https://trusted') }

RateLimitMiddleware

Limits the number of requests per time window per client IP. Supports in-memory and Redis backends.

Via ApplicationOptions.rateLimit

typescript
const app = new OneBunApplication(AppModule, {
  rateLimit: {
    windowMs: 15 * 60 * 1000,  // 15 minutes
    max: 200,                   // 200 requests per window
  },
});

Pass rateLimit: true for defaults (100 requests / 60 seconds, in-memory, IP-based).

Redis-backed (multi-instance)

typescript
import { RateLimitMiddleware, RedisRateLimitStore } from '@onebun/core';
import { SharedRedisProvider } from '@onebun/core';

const redis = await SharedRedisProvider.getClient();

const app = new OneBunApplication(AppModule, {
  middleware: [
    RateLimitMiddleware.configure({
      windowMs: 60_000,
      max: 100,
      store: new RedisRateLimitStore(redis),
    }),
  ],
});

Custom key generator

typescript
RateLimitMiddleware.configure({
  max: 50,
  windowMs: 60_000,
  keyGenerator: (req) => req.headers.get('x-api-key') ?? 'anon',
})

RateLimitOptions

PropertyTypeDefaultDescription
windowMsnumber60_000Time window in ms
maxnumber100Max requests per window
keyGenerator(req) => stringIP from x-forwarded-forKey for grouping requests
messagestring'Too Many Requests'Error message when limit exceeded
standardHeadersbooleantrueAdd RateLimit-* headers
legacyHeadersbooleanfalseAdd X-RateLimit-* headers
storeRateLimitStoreMemoryRateLimitStoreStorage backend

Rate limit response (HTTP 429)

json
{
  "success": false,
  "error": "Too Many Requests",
  "statusCode": 429
}

Response headers (when standardHeaders: true):

  • RateLimit-Limit: 100
  • RateLimit-Remaining: 0
  • RateLimit-Reset: 42 (seconds until window resets)

SecurityHeadersMiddleware

Sets security-related HTTP response headers on every response — analogous to helmet.

Via ApplicationOptions.security

typescript
// All defaults
const app = new OneBunApplication(AppModule, { security: true });

// Custom configuration
const app = new OneBunApplication(AppModule, {
  security: {
    contentSecurityPolicy: "default-src 'self'; img-src *",
    strictTransportSecurity: false,  // disable HSTS in development
  },
});

Default headers set

HeaderDefault value
Content-Security-Policydefault-src 'self'
Cross-Origin-Opener-Policysame-origin
Cross-Origin-Resource-Policysame-origin
Origin-Agent-Cluster?1
Referrer-Policyno-referrer
Strict-Transport-Securitymax-age=15552000; includeSubDomains
X-Content-Type-Optionsnosniff
X-DNS-Prefetch-Controloff
X-Download-Optionsnoopen
X-Frame-OptionsSAMEORIGIN
X-Permitted-Cross-Domain-Policiesnone
X-XSS-Protection0 (disabled — use CSP instead)

SecurityHeadersOptions

Each property accepts a string (custom value) or false (disable the header entirely).

typescript
security: {
  contentSecurityPolicy: "default-src 'self'; connect-src 'self' https://api.example.com",
  xFrameOptions: 'DENY',
  strictTransportSecurity: false,  // disable in local dev
}

Implementing a Custom Store

You can plug in any storage backend by implementing the RateLimitStore interface:

typescript
import type { RateLimitStore } from '@onebun/core';

class MyCustomStore implements RateLimitStore {
  async increment(
    key: string,
    windowMs: number,
  ): Promise<{ count: number; resetAt: number }> {
    // ...custom logic...
    return { count: 1, resetAt: Date.now() + windowMs };
  }
}

const app = new OneBunApplication(AppModule, {
  middleware: [
    RateLimitMiddleware.configure({ store: new MyCustomStore() }),
  ],
});

Released under the LGPL-3.0 License.