Add brute-force protection to login endpoint #637

Open
pook wants to merge 62 commits from feat/login-brute-force-protection into main
Owner

Summary

  • Adds POST /api/auth/login endpoint with account lockout after 5 consecutive failed password attempts (15-minute lockout window)
  • Adds password_hash, failed_login_attempts, and locked_until columns to users table via Drizzle schema + SQL migration
  • IP-based rate limiting (10 req/min) on /api/auth/* using existing rate limiter middleware
  • Returns 429 when locked, generic 401 for wrong credentials (no information leakage about email existence)
  • Successful login resets the failed attempt counter

Test plan

  • 11 unit tests covering: missing fields (400), wrong password (401), non-existent user (401), no email existence leak, failed attempt counter increment, lockout after 5 failures, 429 on locked account, login after lockout expires, counter reset on success, no sensitive fields in response, no lock under 5 attempts
  • TypeScript type check passes (npx tsc --noEmit)
  • All existing tests remain green (219/220 pass — 1 pre-existing failure in document-generator unrelated to this change)

🤖 Generated with Claude Code

## Summary - Adds `POST /api/auth/login` endpoint with account lockout after 5 consecutive failed password attempts (15-minute lockout window) - Adds `password_hash`, `failed_login_attempts`, and `locked_until` columns to users table via Drizzle schema + SQL migration - IP-based rate limiting (10 req/min) on `/api/auth/*` using existing rate limiter middleware - Returns 429 when locked, generic 401 for wrong credentials (no information leakage about email existence) - Successful login resets the failed attempt counter ## Test plan - [x] 11 unit tests covering: missing fields (400), wrong password (401), non-existent user (401), no email existence leak, failed attempt counter increment, lockout after 5 failures, 429 on locked account, login after lockout expires, counter reset on success, no sensitive fields in response, no lock under 5 attempts - [x] TypeScript type check passes (`npx tsc --noEmit`) - [x] All existing tests remain green (219/220 pass — 1 pre-existing failure in document-generator unrelated to this change) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Add brute-force protection to login endpoint
Some checks are pending
CI Quality Gate / Lint / Typecheck / Test / Build (pull_request) Waiting to run
3cd7c73679
Implements account lockout after 5 consecutive failed login attempts,
locking the account for 15 minutes. Adds password_hash, failed_login_attempts,
and locked_until columns to users table. Returns 429 when locked and generic
401 for wrong credentials to prevent information leakage. Includes IP-based
rate limiting (10 req/min) on the auth endpoint and 11 unit tests covering
lockout, unlock, counter reset, and no-leak behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat: issue #635 the-login-endpoint-lacks-brute-force-pro (agent task liancebot635)
Some checks failed
CI Quality Gate / Lint / Typecheck / Test / Build (pull_request) Has been cancelled
510ad2d471
Some checks failed
CI Quality Gate / Lint / Typecheck / Test / Build (pull_request) Has been cancelled
This pull request has changes conflicting with the target branch.
  • .forgejo/workflows/ci.yml
  • bun.lock
  • package.json
  • packages/api/src/db/schema.ts
  • packages/api/src/index.ts
  • packages/api/src/middleware/csrf.ts
  • packages/api/src/middleware/rate-limit.ts
  • packages/api/src/middleware/security-headers.ts
  • packages/api/src/routes/admin.ts
  • packages/api/src/routes/auth.ts
  • packages/api/src/routes/billing.ts
  • packages/api/src/routes/generate-tos.ts
  • packages/api/src/routes/generate.ts
  • packages/api/src/routes/health.ts
  • packages/api/src/routes/questionnaire.ts
  • packages/api/src/services/document-generator.ts
  • packages/api/src/services/llm.ts
  • packages/api/src/templates/index.ts
  • packages/api/tsconfig.json
  • packages/shared/src/types.ts
  • packages/web/src/app/questionnaire/page.tsx
  • packages/web/src/components/documents/DocumentList.tsx
  • packages/web/src/components/questionnaire/ReviewStep.tsx
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/login-brute-force-protection:feat/login-brute-force-protection
git switch feat/login-brute-force-protection
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pook/compliancebot!637
No description provided.