danielmichaels / danielmichaels/gecko

Rate-limit auth endpoints (login / signup / invite-accept)

Open
#29 0 comments 0 reactions 0 assignees View on GitHub
enhancement security
Dominant language
Go
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Summary

The unauthenticated auth endpoints have **no rate limiting**, leaving them open to password brute-force and email enumeration.

## Evidence

- `internal/server/routes.go` — `/api/auth/login`, `/api/auth/signup`, `/api/invitations/accept` are registered with no throttle.
- `internal/server/server.go` — the middleware chain is `Recoverer`, `RealIP`, `traceMiddleware`, `compressExceptSSE`, `httplog`, `recordSSEStatus`. No rate limiter.
- A `PgRateLimiter` exists for the DNS resolver layer (`internal/dnsclient`) but nothing equivalent guards the HTTP API.

## Why it matters

- **Brute-force:** unlimited `/login` attempts against any known email.
- **Enumeration:** signup/invite-accept responses can distinguish valid vs invalid accounts.
- Also protects the browser UI login (same service path).

## Design considerations (flag before implementing)

- **Per-IP vs per-account:** per-IP throttling is simplest but evadable behind NAT/proxies; per-account (email) protects a specific user but enables a lockout-DoS. Consider both with different windows.
- **Store:** in-memory limiter (e.g. `chi`/`tollbooth`/`golang.org/x/time/rate`) is simplest but per-instance — won't hold across a horizontally-scaled deployment. A Postgres-backed limiter (reuse the `PgRateLimiter` pattern) is fleet-wide consistent but adds DB load on every auth hit. **Flag this CAP/cost trade-off explicitly when picking an approach.**
- `RealIP` is already in the chain, so the client IP is available — but confirm it's only trusted behind a known proxy (header spoofing otherwise).

## Acceptance criteria

- [ ] Login/signup/invite-accept are rate-limited; limits are configurable via env (`internal/config`).
- [ ] Exceeding the limit returns `429` with a `Retry-After`.
- [ ] Decision on per-IP vs per-account documented in the PR.
- [ ] Tests covering the limit boundary.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with internal/server/routes.go and internal/server/server.go to trace the three auth endpoints and current middleware chain, then inspect internal/config and the existing PgRateLimiter pattern in internal/dnsclient. Before implementation, document the per-IP versus per-account and in-memory versus Postgres-backed decision; done means configurable limits, 429 responses with Retry-After, and boundary tests for login, signup, and invite-accept.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, postgresql
Domain
api, authentication, backend, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.