RateLimitByAuthToken returns a handler that limits requests based on the authentication token in the request. This differs from [RateLimit] in several ways: - It extracts the token directly from request headers (Authorization Bearer or X-Api-Key) rather than from the request context, making it suit
(count int, window time.Duration)
| 109 | // |
| 110 | // If no token is found in the headers, it falls back to rate limiting by IP address. |
| 111 | func RateLimitByAuthToken(count int, window time.Duration) func(http.Handler) http.Handler { |
| 112 | if count <= 0 { |
| 113 | return func(handler http.Handler) http.Handler { |
| 114 | return handler |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | return httprate.Limit( |
| 119 | count, |
| 120 | window, |
| 121 | httprate.WithKeyFuncs(func(r *http.Request) (string, error) { |
| 122 | // Try to extract auth token for per-user rate limiting using |
| 123 | // AI provider authentication headers (Authorization Bearer or X-Api-Key). |
| 124 | if token := aibridge.ExtractAuthToken(r.Header); token != "" { |
| 125 | return token, nil |
| 126 | } |
| 127 | // Fall back to IP-based rate limiting if no token present. |
| 128 | return httprate.KeyByIP(r) |
| 129 | }), |
| 130 | httprate.WithLimitHandler(func(w http.ResponseWriter, r *http.Request) { |
| 131 | // Add Retry-After header for backpressure signaling. |
| 132 | w.Header().Set("Retry-After", fmt.Sprintf("%d", int(window.Seconds()))) |
| 133 | httpapi.Write(r.Context(), w, http.StatusTooManyRequests, codersdk.Response{ |
| 134 | Message: "You've been rate limited. Please try again later.", |
| 135 | }) |
| 136 | }), |
| 137 | ) |
| 138 | } |
| 139 | |
| 140 | // ConcurrencyLimit returns a handler that limits the number of concurrent |
| 141 | // requests. When the limit is exceeded, it returns HTTP 503 Service Unavailable. |