diff --git a/dashcaddy-api/src/utilities/middleware.js b/dashcaddy-api/src/utilities/middleware.js index 9620198..f871dcd 100644 --- a/dashcaddy-api/src/utilities/middleware.js +++ b/dashcaddy-api/src/utilities/middleware.js @@ -507,9 +507,26 @@ module.exports = function configureMiddleware(app, { }); app.use('/api/v1/auth/keys', authLimiter); app.use('/api/v1/auth/jwt', authLimiter); - app.use('/api/v1/auth/gate', authLimiter); app.use('/api/v1/auth/app-token', authLimiter); + // Separate, much higher limit for /auth/gate/* — Caddy's forward_auth + // fires this on EVERY page-load asset (HTML, JS, CSS, XHR, image refs) + // for every gated service. With multiple service tabs open + dashboard + // health probes, 20/15min burns in under a minute. Real brute-force + // risk is on /auth/keys + /auth/jwt + /auth/app-token (above); gate + // doesn't mint or return secrets directly (Caddy uses the response + // headers to inject Basic Auth / X-Api-Key into the upstream call, + // which still requires a valid auth cookie upstream). + const authGateLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 600, // 40/min average — accommodates ~6 service tabs each polling every 15s + standardHeaders: true, + legacyHeaders: false, + skip: (req) => isTest || req.auth?.type === 'session' || req.auth?.type === 'jwt' || req.auth?.type === 'apikey', + message: { success: false, error: 'Too many auth requests, please try again later' } + }); + app.use('/api/v1/auth/gate', authGateLimiter); + // ── Audit logging middleware (logs non-GET API requests) ── app.use(auditLogger.middleware());