Skip to content

feat: Implement rate limiting for /workspace and ChatKit to prevent billing abuse #30

Description

@mjunaidca

Problem

Currently, there is no rate limiting on the web application. A single user could:

  • Spam ChatKit messages and rack up AI billing costs
  • Overwhelm the API with excessive requests
  • Impact other users' experience

The /workspace page with ChatKit integration is the highest risk area.


Context

  • Deployment: Kubernetes cluster
  • Dapr: Sidecar available (can be attached to web project)
  • Current state: Zero rate limiting infrastructure

Scope of Work

Files to Modify/Create

File Change Purpose
apps/web/src/lib/rate-limit.ts NEW Dapr state-backed rate limiter
apps/web/src/app/api/chatkit/route.ts Add rate check Protect AI billing
apps/web/src/app/api/proxy/[...path]/route.ts Add rate check General API protection
components/ratelimit-statestore.yaml NEW (if needed) Dapr state component
K8s deployment annotations Update Attach Dapr sidecar

Rate Limits (Proposed)

Endpoint Limit Window Rationale
/api/chatkit 20 messages 1 minute AI billing protection
/api/proxy/* 200 requests 1 minute General abuse prevention

Implementation Options

Option A: Dapr Built-in Rate Limit Middleware (Simplest)

  • Pros: Config-only, no code changes
  • Cons: Global rate limit, not per-user

Option B: Dapr State Store + Code (Recommended)

  • Pros: Per-user limits, distributed across pods, window-based
  • Cons: Requires state store component

Option C: Redis Sidecar

  • Pros: Battle-tested, feature-rich
  • Cons: Additional dependency to manage

Questions to Answer Before Implementation

  • Q1: Is Dapr sidecar already attached to the web deployment?
  • Q2: Do we have a Dapr state store component configured (Redis/PostgreSQL)?
  • Q3: What's the current replica count for web pods?
  • Q4: Should rate limit violations be logged to the audit table?
  • Q5: Do we need different limits for authenticated vs unauthenticated users?
  • Q6: Should we expose rate limit headers (X-RateLimit-Remaining, Retry-After)?

Technical Details

User Identification

  • JWT sub claim available from taskflow_id_token cookie
  • Already extracted in proxy route (line 58-60)

Integration Points

  • apps/web/src/app/api/proxy/[...path]/route.ts:58-60 - JWT extraction
  • apps/web/src/app/api/chatkit/route.ts - ChatKit proxy
  • apps/api/src/taskflow_api/main.py:85-92 - Backend middleware (optional)

Response on Rate Limit

{
  "error": "Rate limit exceeded. Try again in 45s"
}

HTTP Status: 429 Too Many Requests
Header: Retry-After: 45


Estimation

Scenario Effort
Dapr already configured 2-3 hours
Need to set up Dapr state 4-5 hours
Full Redis setup 6-8 hours

Acceptance Criteria

  • ChatKit messages rate limited to 20/min per user
  • API requests rate limited to 200/min per user
  • Rate limits work across all K8s pods (distributed)
  • Users see clear error message when rate limited
  • No impact on other users when one user hits limit
  • Zero downtime deployment

Labels

enhancement security billing apps/web

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions