Skip to content

feat: rate limit authentication endpoints#115

Merged
GitAddRemote merged 6 commits intomainfrom
fix/ISSUE-95-rate-limiting
Apr 16, 2026
Merged

feat: rate limit authentication endpoints#115
GitAddRemote merged 6 commits intomainfrom
fix/ISSUE-95-rate-limiting

Conversation

@GitAddRemote
Copy link
Copy Markdown
Owner

@GitAddRemote GitAddRemote commented Apr 11, 2026

Summary

  • Registers `ThrottlerModule` globally in `AppModule` with configurable default limits (100 req / 60s via `THROTTLE_LIMIT` / `THROTTLE_TTL_MS` env vars)
  • Applies `CustomThrottlerGuard` as a global `APP_GUARD`; uses `req.ips` (Express proxy-aware) instead of raw `X-Forwarded-For` to prevent IP spoofing
  • Adds stricter per-endpoint `@Throttle` limits on sensitive auth routes:
    • `POST /auth/login`: 10 req / 60s (`AUTH_LOGIN_THROTTLE_LIMIT` / `AUTH_LOGIN_THROTTLE_TTL_MS`)
    • `POST /auth/register`: 5 req / 60s (`AUTH_REGISTER_THROTTLE_LIMIT` / `AUTH_REGISTER_THROTTLE_TTL_MS`)
    • `POST /auth/forgot-password`: 5 req / 60s (`AUTH_FORGOT_THROTTLE_LIMIT` / `AUTH_FORGOT_THROTTLE_TTL_MS`)
  • All TTL env vars use the `_MS` suffix to make millisecond units unambiguous
  • Per-route constants are parsed with `Number()` + `isFinite` validation; invalid values fall back to hardcoded defaults
  • `dotenv/config` is now the first import in `main.ts` so `.env` values are visible to module-level code (decorator arguments, top-level constants) before any other module is evaluated
  • 429 responses include `Retry-After` header via ThrottlerGuard defaults
  • Updated `.env.example` with all new rate-limiting variables

Test plan

  • Start the backend with `pnpm dev:backend`
  • Hit `POST /auth/login` 11 times within 60 seconds — expect 429 on the 11th with a `Retry-After` header
  • Verify normal endpoints (e.g. `GET /`) still accept traffic up to the 100-req default limit
  • Set `AUTH_LOGIN_THROTTLE_LIMIT=3` in `.env` and verify 429 occurs on the 4th request
  • e2e: `pnpm test:e2e` — `auth-rate-limit.e2e-spec.ts` asserts 429 + `Retry-After` header

Closes #95

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds application-level rate limiting using @nestjs/throttler, with a global default throttle and tighter limits on high-risk authentication endpoints to mitigate brute force and abuse.

Changes:

  • Add @nestjs/throttler dependency.
  • Register ThrottlerModule globally and apply ThrottlerGuard as a global APP_GUARD.
  • Add per-route @Throttle() overrides for /auth/login, /auth/register, and /auth/forgot-password, and document env vars in .env.example.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pnpm-lock.yaml Locks @nestjs/throttler dependency resolution.
backend/package.json Adds @nestjs/throttler dependency.
backend/src/app.module.ts Configures global throttler defaults and installs ThrottlerGuard globally.
backend/src/modules/auth/auth.controller.ts Adds stricter per-endpoint throttling for sensitive auth routes.
backend/.env.example Documents new rate-limit env variables and defaults.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/src/modules/auth/auth.controller.ts Outdated
Comment thread backend/src/modules/auth/auth.controller.ts Outdated
Comment thread backend/src/modules/auth/auth.controller.ts Outdated
Comment thread backend/src/modules/auth/auth.controller.ts Outdated
Comment thread backend/src/app.module.ts Outdated
Comment thread backend/src/app.module.ts
Comment thread backend/.env.example Outdated
@GitAddRemote GitAddRemote self-assigned this Apr 12, 2026
Register ThrottlerModule globally with configurable default limits (100 req/60s).
Apply stricter per-endpoint limits on auth routes via @Throttle decorator:
- POST /auth/login: 10 req/60s (AUTH_LOGIN_THROTTLE_LIMIT/TTL)
- POST /auth/register: 5 req/60s (AUTH_REGISTER_THROTTLE_LIMIT/TTL)
- POST /auth/forgot-password: 5 req/60s (AUTH_FORGOT_THROTTLE_LIMIT/TTL)

All limits are env-configurable. ThrottlerGuard applied as global APP_GUARD.
429 responses include Retry-After header via ThrottlerGuard defaults.

Closes #95
@GitAddRemote GitAddRemote force-pushed the fix/ISSUE-95-rate-limiting branch from 1db55b8 to 4602f86 Compare April 13, 2026 00:23
Review item fixes:

- Replace parseInt() in @Throttle decorators with Number() + isFinite

  validation via toThrottleInt() helper; invalid env vars fall back to

  safe defaults rather than silently producing NaN

- Rename *_THROTTLE_TTL env vars to *_THROTTLE_TTL_MS for unambiguous

  unit signalling; update .env.example and all references

- Apply same Number/isFinite validation to THROTTLE_TTL_MS/THROTTLE_LIMIT

  in ThrottlerModule.forRootAsync factory in app.module.ts

- Add CustomThrottlerGuard (src/common/guards/throttler.guard.ts) that

  reads X-Forwarded-For header for proxy-aware client identification;

  register as APP_GUARD in AppModule instead of plain ThrottlerGuard

- Add auth-rate-limit.e2e-spec.ts: exceeds login rate limit and asserts 429

Conflict resolutions:

- .env.example: kept rate-limiting block + added ALLOWED_ORIGIN from main

- auth.controller.ts: kept @Throttle + @httpcode on forgot-password route

- pnpm-lock.yaml: regenerated
Copilot AI review requested due to automatic review settings April 13, 2026 23:15
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/src/app.module.ts
Comment thread backend/test/auth-rate-limit.e2e-spec.ts
Comment thread backend/src/modules/auth/auth.controller.ts
Comment thread backend/src/common/guards/throttler.guard.ts Outdated
- getTracker(): use req.ips[0] (Express proxy-aware) instead of reading

  X-Forwarded-For directly; avoids spoofing when trust proxy is not set

- main.ts: move dotenv/config to first import so process.env is populated

  before any module-level code evaluates it (fixes per-route throttle

  constants not reading .env values during local development)

- e2e test: add Retry-After header assertions (defined, integer, > 0)
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backend/test/auth-rate-limit.e2e-spec.ts Outdated
Comment thread backend/test/auth-rate-limit.e2e-spec.ts
- Replace \`Number(env) || 10\` with \`toThrottleInt()\` to mirror the exact same
  parsing/flooring/fallback logic used in auth.controller.ts; prevents a
  misconfigured env value (e.g. 'Infinity') from hanging the for loop
- Read \`AUTH_LOGIN_THROTTLE_TTL_MS\` via the same helper to derive the expected
  TTL window in seconds
- Add upper-bound assertion: \`Retry-After\` must be <= \`ceil(TTL_MS / 1000)\`;
  a larger value would indicate a unit mismatch or misconfiguration in the
  throttler setup
@GitAddRemote GitAddRemote requested a review from Copilot April 16, 2026 02:37
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 8 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Resolved conflicts:
- backend/.env.example: kept main's sectioned format and FRONTEND_URL;
  added Rate Limiting section under its own header; dropped duplicate
  Application block from HEAD
- backend/src/modules/auth/auth.controller.ts: kept both Throttle import
  (PR-115) and ConfigService import (main/PR-118)
@GitAddRemote GitAddRemote merged commit 5bf1e3b into main Apr 16, 2026
12 checks passed
@GitAddRemote GitAddRemote deleted the fix/ISSUE-95-rate-limiting branch April 16, 2026 03:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tech Story: Rate limit authentication endpoints

2 participants