aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/server/routes/auth.test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/routes/auth.test.ts')
-rw-r--r--src/server/routes/auth.test.ts50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/server/routes/auth.test.ts b/src/server/routes/auth.test.ts
index 5bf9f86..c3b0158 100644
--- a/src/server/routes/auth.test.ts
+++ b/src/server/routes/auth.test.ts
@@ -62,6 +62,56 @@ describe("POST /login", () => {
app.route("/api/auth", auth);
});
+ it("returns rate limit headers on login request", async () => {
+ vi.mocked(mockUserRepo.findByUsername).mockResolvedValue(undefined);
+
+ const res = await app.request("/api/auth/login", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Forwarded-For": "192.168.1.1",
+ },
+ body: JSON.stringify({
+ username: "testuser",
+ password: "somepassword",
+ }),
+ });
+
+ expect(res.headers.get("RateLimit-Limit")).toBe("5");
+ expect(res.headers.get("RateLimit-Remaining")).toBeDefined();
+ });
+
+ it("returns 429 after exceeding rate limit", async () => {
+ vi.mocked(mockUserRepo.findByUsername).mockResolvedValue(undefined);
+
+ const makeRequest = () =>
+ app.request("/api/auth/login", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Forwarded-For": "10.0.0.1",
+ },
+ body: JSON.stringify({
+ username: "testuser",
+ password: "wrongpassword",
+ }),
+ });
+
+ // Make 5 requests (the limit)
+ for (let i = 0; i < 5; i++) {
+ const res = await makeRequest();
+ expect(res.status).toBe(401);
+ }
+
+ // 6th request should be rate limited
+ const rateLimitedRes = await makeRequest();
+ expect(rateLimitedRes.status).toBe(429);
+ const body = (await rateLimitedRes.json()) as {
+ error?: { code: string; message: string };
+ };
+ expect(body.error?.code).toBe("RATE_LIMIT_EXCEEDED");
+ });
+
it("returns access token for valid credentials", async () => {
vi.mocked(mockUserRepo.findByUsername).mockResolvedValue({
id: "user-uuid-123",