Middleware Catalog
Auth
JwtAuthMiddleware— HS256 / asymmetric JWT verification through anyJwtVerifierInterfaceRs256JwksJwtVerifier(v0.6.0) — RS256 / ES256 verifier backed by JWKS; pairs withHttpJwksProvider/StaticJwksProviderBearerTokenAuthMiddlewareHmacSignatureMiddleware(v0.6.0) — HMAC request signatures with replay window; pairs withHmacSecretProviderInterface/ArrayHmacSecretProviderCookieNonceAuthMiddlewareApplicationPasswordAuthMiddlewareWpClaimsUserMapperOwnershipGuardMiddleware(v0.5.0) — route-level "current user owns this resource" guard; pairs withOwnedResourcePolicy::currentUserOwns()for Resource DSL
Write safety
IdempotencyMiddleware— response-replay cache (handler runs, then store writes)TransientIdempotencyStoreWpdbIdempotencyStore(v0.3.0) —wpdb-backed replay store; callinstallSchema()once on activationAtomicIdempotencyMiddleware(v0.5.0) — reserves the key before handler execution; blocks concurrent retries with409 idempotency_in_progressAtomicIdempotencyStoreInterface(v0.5.0) — store contract (reserve/complete/release)ArrayAtomicIdempotencyStore(v0.5.0) — in-memory store for tests / non-productionWpdbAtomicIdempotencyStore(v0.5.0) —wpdbINSERT IGNOREreservation store; dedicated table,installSchema()once on activationSingleUseTokenMiddleware(v0.6.0) — atomic one-time token consumption (OAuth codes, magic links, password resets)SingleUseTokenStoreInterface(v0.6.0) — store contract (consume/store/wasConsumed)ArraySingleUseTokenStore(v0.6.0) — in-memory store for testsWpdbSingleUseTokenStore(v0.6.0) —wpdb-backed token store with TTL pruning;installSchema()once on activationWpCacheSingleUseTokenStore(v0.6.0) — object-cache lock + transient-backed recordsOptimisticLockMiddlewareCallbackOptimisticLockVersionResolver
Public-client / CORS (v0.5.0)
BetterRoute\Middleware\Cors\CorsMiddleware— applies aCorsPolicy, short-circuits preflightOPTIONSwith204BetterRoute\Middleware\Cors\CorsPolicy— origin allowlist, methods/headers/exposed-headers, credentials, max ageRouter::options()— register explicit preflight routes;OPTIONSpermissions are public-by-default
Network (v0.6.0)
BetterRoute\Middleware\Network\TrustedProxyClientIpResolver— trusted-proxy aware client IP resolution; implementsClientIpResolverInterfaceBetterRoute\Middleware\Network\ClientIpResolverInterface— minimalresolve(?mixed $request = null): ?stringcontractBetterRoute\Middleware\Network\IpAllowlistMiddleware— denies requests outside an IPv4/IPv6 CIDR allowlistBetterRoute\Middleware\Network\CidrMatcher— IPv4/IPv6 aware CIDR / single-host matcher
Rate limiting
RateLimitMiddleware— (v0.6.0)clientIpResolvernow accepts eitherHttp\ClientIpResolverorMiddleware\Network\ClientIpResolverInterfaceTransientRateLimiterWpObjectCacheRateLimiter(v0.3.0) — uses the WP object cache; throwsRuntimeExceptionifwp_cache_*is unavailable
Caching
CachingMiddlewareTransientCacheStoreETagMiddleware(v0.3.0) — emitsETagheaders and replies304 Not ModifiedonIf-None-Matchmatches (GET/HEAD only)
HTTP infrastructure
BetterRoute\Http\ClientIpResolver— kept stable since v0.3.0; (v0.6.0) now delegates internally toTrustedProxyClientIpResolver. Constructor andresolve(?array $server = null)API unchanged. New code should preferTrustedProxyClientIpResolverdirectly.BetterRoute\Http\OAuthErrorNormalizer(v0.6.0) — emits OAuth RFC 6749 style error bodies when a route opts in viameta(['error_format' => 'oauth_rfc6749']). See OAuth Error Format.
Support utilities (v0.6.0)
BetterRoute\Support\Crypto— CSPRNG token generation, hex/base64/base64url encoding, strict base64url decoding, constant-time compare. See Crypto Utilities.BetterRoute\Support\CryptoEncoding— enum (Hex,Base64,Base64Url).
Observability
AuditMiddleware— (v0.5.0) now mergesRequestContext::$attributes['audit']into emitted eventsAuditEnricherMiddleware(v0.5.0) — adds auth provider/user/subject, hashed idempotency key, optional client IP, and static fields to theauditattributeErrorLogAuditLoggerMetricsMiddlewareInMemoryMetricSinkPrometheusMetricSinkAuditEventFactory
Typical global stack
$router->middleware([
new MetricsMiddleware(new PrometheusMetricSink()),
new AuditMiddleware(new ErrorLogAuditLogger()),
new RateLimitMiddleware(new TransientRateLimiter(), limit: 100, windowSeconds: 60),
]);
Order recommendation:
- CORS (preflight short-circuit before anything else)
- IP allowlist (drop unauthorized networks early)
- Metrics/Audit (outer visibility)
- Rate limit
- Auth (JWT, HMAC, cookie/nonce, application password)
- Ownership / single-use token / cache / idempotency / optimistic lock
- business handler
Default keys (v0.3.0)
CachingMiddleware, IdempotencyMiddleware, and RateLimitMiddleware derive default keys from request identity:
auth.userId > 0→"{provider}:user:{userId}"auth.subject(non-empty) →"{provider}:sub:{subject}"RateLimitMiddlewareonly: client IP fallback →"ip:{clientIp}"- otherwise →
"guest"
If you previously relied on the v0.2.0 route-only defaults, expect a one-time cache miss after upgrade. Pass an explicit keyResolver to keep keys stable.