diff --git a/apps/api/src/middleware/rateLimiters.test.ts b/apps/api/src/middleware/rateLimiters.test.ts index 29a219f..3bcccbb 100644 --- a/apps/api/src/middleware/rateLimiters.test.ts +++ b/apps/api/src/middleware/rateLimiters.test.ts @@ -5,7 +5,6 @@ import { authLimiter, gameLimiter, lobbyLimiter } from "./rateLimiters.js"; import type { Session, User } from "better-auth"; -// Minimal app to test the limiter in isolation function createTestApp() { const app = express(); app.set("trust proxy", 1); @@ -20,29 +19,51 @@ describe("authLimiter", () => { let app: ReturnType; beforeEach(() => { - // Fresh app = fresh in-memory store = counters reset between tests app = createTestApp(); }); - it("allows requests under the limit through", async () => { + it("allows requests under the limit through on sensitive endpoints", async () => { const res = await request(app).post("/api/auth/sign-in"); expect(res.status).toBe(200); }); - it("returns 429 after exceeding the limit", async () => { + it("returns 429 after exceeding the limit on sensitive endpoints", async () => { const limit = 20; for (let i = 0; i < limit; i++) { await request(app).post("/api/auth/sign-in"); } const res = await request(app).post("/api/auth/sign-in"); expect(res.status).toBe(429); - expect(res.body).toEqual({ - success: false, - error: "Too many requests, please try again later.", - }); }); - it("sets RateLimit headers on responses", async () => { + it("does not rate limit /get-session", async () => { + const limit = 20; + for (let i = 0; i < limit + 5; i++) { + await request(app).get("/api/auth/get-session"); + } + const res = await request(app).get("/api/auth/get-session"); + expect(res.status).toBe(200); + }); + + it("does not rate limit /sign-out", async () => { + const limit = 20; + for (let i = 0; i < limit + 5; i++) { + await request(app).post("/api/auth/sign-out"); + } + const res = await request(app).post("/api/auth/sign-out"); + expect(res.status).toBe(200); + }); + + it("does not rate limit OAuth callbacks", async () => { + const limit = 20; + for (let i = 0; i < limit + 5; i++) { + await request(app).get("/api/auth/callback/google"); + } + const res = await request(app).get("/api/auth/callback/google"); + expect(res.status).toBe(200); + }); + + it("sets RateLimit headers on sensitive responses", async () => { const res = await request(app).post("/api/auth/sign-in"); expect(res.headers).toHaveProperty("ratelimit"); }); diff --git a/apps/api/src/middleware/rateLimiters.ts b/apps/api/src/middleware/rateLimiters.ts index 479be03..2f2eaf6 100644 --- a/apps/api/src/middleware/rateLimiters.ts +++ b/apps/api/src/middleware/rateLimiters.ts @@ -13,6 +13,15 @@ export const authLimiter = rateLimit({ limit: 20, standardHeaders: "draft-8", legacyHeaders: false, + skip: (req) => { + const path = req.path; + return ( + path.includes("/get-session") || + path.includes("/sign-out") || + path.startsWith("/callback/") || + path.includes("/callback/") + ); + }, message: { success: false, error: "Too many requests, please try again later.",