middleware config
- Source:
src/config/middleware.ts
Usage
Import from the framework:
ts
import { middleware } from '@zintrust/core';
// Example (if supported by the module):
// middleware.*Snapshot (top)
ts
import { MiddlewareConfigType } from '@zintrust/core';
import {
CsrfMiddleware,
ErrorHandlerMiddleware,
LoggingMiddleware,
type Middleware,
RateLimiter,
SecurityMiddleware,
} from '@zintrust/core';
const shared = Object.freeze({
log: LoggingMiddleware.create(),
error: ErrorHandlerMiddleware.create(),
security: SecurityMiddleware.create(),
rateLimit: RateLimiter.create(),
csrf: CsrfMiddleware.create({
// Default: do not bypass CSRF.
// Optional: bypass CSRF for path patterns (simple `*` glob), e.g. ['/api/*'].
skipPaths: [],
}),
} satisfies Record\<string, Middleware>);
const middlewareConfigObj: MiddlewareConfigType = {
global: [shared.log, shared.error, shared.security, shared.rateLimit, shared.csrf],
route: shared,
};
export const middlewareConfig = Object.freeze(middlewareConfigObj);
export default middlewareConfig;CSRF Redis Store (new)
- What changed:
CsrfTokenManagernow supports a Redis-backed store in addition to the in-memory Map. The implementation uses the project'sRedisKeys.getCsrfPrefix()for key namespacing and stores token payloads with Redis TTLs so Redis expiry is relied upon for cleanup. - How to enable: Set
CSRF_STORE=redis(orCSRF_DRIVER=redis) in your environment. Optionally setCSRF_REDIS_DBto choose a Redis DB index; otherwise the queue/cache Redis DB settings are used. The manager will create/connect to Redis using the existingREDIS_*env settings (REDIS_HOST,REDIS_PORT,REDIS_PASSWORD). - Key format: Keys are created via
RedisKeys.createCsrfKey(sessionId)(prefix fromRedisKeys.getCsrfPrefix()), e.g.{appPrefix}_csrf:{sessionId}. - Behavioral notes:
- Tokens are stored as JSON blobs and saved with a TTL (PX) matching the configured token TTL (
TOKEN_TTL). - Cleanup operations are effectively no-ops for Redis (expiry handled by Redis). The
cleanup()method returns 0 for Redis but the API remains compatible. - Scanning/clear operations use
SCANwithMATCH {csrfPrefix}*andDELfor explicit removal; avoid clearing large datasets in production without care.
- Tokens are stored as JSON blobs and saved with a TTL (PX) matching the configured token TTL (
- Security & performance:
- Using Redis allows CSRF tokens to be shared across multiple app instances (horizontal scale) and avoids reliance on sticky sessions.
- Monitor Redis keyspace and avoid storing unnecessarily long TTLs; token TTL defaults are driven by
TOKEN_TTL.
- Tests & templates: Middleware and tests were updated to the async API (
generateToken/validateTokennow return Promises). Ensure any custom code calling the CSRF manager is updated toawaitthe async calls.
CSRF skip paths
ZinTrust CSRF uses a Double Submit Cookie pattern (cookie + header). If your application is a pure API consumed with Authorization: Bearer ... (no cookie-based auth), you may prefer to bypass CSRF for API routes.
- Configure via
CSRF_SKIP_PATHSenvironment variable:CSRF_SKIP_PATHS=/api/*,/hooks/* - Or manually via code:
CsrfMiddleware.create({ skipPaths: [...] }) - Patterns support simple glob matching where
*matches any characters (example:'/api/*')
Dev Reload Notes
In ZinTrust, middleware config is created once and cached in-memory for the lifetime of the running Node process. The HTTP Kernel also snapshots the resolved middleware list when it is created.
That means changes to src/config/middleware.ts (or other config modules) typically require a process restart to take effect.
- Use
zin sduring development: it restarts the server process when code/config changes, so updated config is picked up automatically. - If you run the server manually (e.g.
node ...), you must stop/restart it to apply config changes.
Snapshot (bottom)
ts
import { MiddlewareConfigType } from '@zintrust/core';
import {
CsrfMiddleware,
ErrorHandlerMiddleware,
LoggingMiddleware,
type Middleware,
RateLimiter,
SecurityMiddleware,
} from '@zintrust/core';
const shared = Object.freeze({
log: LoggingMiddleware.create(),
error: ErrorHandlerMiddleware.create(),
security: SecurityMiddleware.create(),
rateLimit: RateLimiter.create(),
csrf: CsrfMiddleware.create(),
} satisfies Record\<string, Middleware>);
const middlewareConfigObj: MiddlewareConfigType = {
global: [shared.log, shared.error, shared.security, shared.rateLimit, shared.csrf],
route: shared,
};
export const middlewareConfig = Object.freeze(middlewareConfigObj);
export default middlewareConfig;