Goal
Protect the expensive /api/query endpoint from scripted abuse / cost-draining. Every call to /api/query fans out to Vertex AI RAG + Gemini, so unthrottled traffic is a direct cost and availability risk.
Current state (June 2026)
- Only two routes exist:
/api/query (chat) and /api/feedback. The endpoints originally named in this issue (/api/history, /api/clear-session, /api/init, /api/citation) were removed when session state moved client-side — the frontend now posts the full message history per request, so there's no server-side session to lock down.
- Already in place: strict CORS origin validation and
flask_limiter.
- The gap: the rate limit is currently applied only to
/api/feedback. The costly /api/query endpoint has no rate limit and no bot protection.
Scope
- Apply a rate limit to
/api/query (primary fix — flask_limiter is already wired up).
- (Optional follow-up) Add bot mitigation — Cloudflare Turnstile (fully free) or hCaptcha (free tier), via a token verified server-side. Only pursue if the rate limiter proves insufficient against distributed/bot abuse.
Explicitly out of scope
User authentication (JWT / OAuth / login sessions). This is an anonymous public legal-aid tool for tenants in crisis; requiring login adds friction for exactly the users we want to reach. Abuse protection, not identity, is the actual need.
Original issue text (stale — kept for history)
Before implementing feedback, we'll need to lock down our API endpoints with some authentication solution to prevent potential exploits.
One potential solution would be with tokens.
Why stale: This was written against a session-based API with five endpoints, four of which no longer exist, and framed the solution as authentication. The architecture is now stateless (client holds message history) and the realistic threat is abuse of the costly LLM endpoint — addressed by rate limiting, not user auth.
Goal
Protect the expensive
/api/queryendpoint from scripted abuse / cost-draining. Every call to/api/queryfans out to Vertex AI RAG + Gemini, so unthrottled traffic is a direct cost and availability risk.Current state (June 2026)
/api/query(chat) and/api/feedback. The endpoints originally named in this issue (/api/history,/api/clear-session,/api/init,/api/citation) were removed when session state moved client-side — the frontend now posts the full message history per request, so there's no server-side session to lock down.flask_limiter./api/feedback. The costly/api/queryendpoint has no rate limit and no bot protection.Scope
/api/query(primary fix —flask_limiteris already wired up).Explicitly out of scope
User authentication (JWT / OAuth / login sessions). This is an anonymous public legal-aid tool for tenants in crisis; requiring login adds friction for exactly the users we want to reach. Abuse protection, not identity, is the actual need.
Original issue text (stale — kept for history)
Why stale: This was written against a session-based API with five endpoints, four of which no longer exist, and framed the solution as authentication. The architecture is now stateless (client holds message history) and the realistic threat is abuse of the costly LLM endpoint — addressed by rate limiting, not user auth.