# API Rate Limits Differentiated by Role

- **Pattern:** `ab-002271` (`saas-authorization.api-auth.api-rate-limit-per-role`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002271
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002271)

## Why it matters

A single global rate limit applied identically to free users, paid users, and admins means the limit must be conservative enough for the most restricted tier — which throttles legitimate premium users — or generous enough for heavy users — which provides no abuse protection for the free tier. CWE-284 (Improper Access Control) covers the failure to differentiate resource access by privilege level. OWASP A01 (Broken Access Control) and NIST 800-53 AC-6 (Least Privilege) require that access controls reflect the actual entitlement model, which for API rate limits means tier-aware limits that match the product's promise to each user segment.

## Severity rationale

Low because absent role-differentiated limits degrades product experience and cost controls rather than enabling direct data exfiltration.

## Remediation

Implement tiered rate limits keyed by the user's subscription plan. Free, pro, and admin tiers each get limits appropriate to their entitlement.

```typescript
// lib/rate-limit.ts
import { Ratelimit } from '@upstash/ratelimit';

const limits = {
  free: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(50, '1 h') }),
  pro:  new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(500, '1 h') }),
  admin: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(5000, '1 h') }),
};

export async function applyRateLimit(userId: string, plan: 'free' | 'pro' | 'admin') {
  const { success } = await limits[plan].limit(userId);
  return success;
}
```

Derive the `plan` from the authenticated session — never from a user-supplied header or query parameter.

## Detection

- **ID:** `api-rate-limit-per-role`
- **Severity:** `low`
- **What to look for:** Count all relevant instances and enumerate each. Look for rate limiting implementation — Upstash Rate Limit, `@upstash/ratelimit`, `express-rate-limit`, or custom rate limiting logic. If rate limiting exists, check whether the limits vary based on user role or subscription plan. A single global limit applied identically to free and paid users, or to users and admins, is a partial fail.
- **Pass criteria:** Rate limits are implemented and differentiated based on user role or subscription tier (e. At least 1 implementation must be verified.g., free users: 50 requests/hour, paid users: 500 requests/hour, admin users: unlimited or higher limit).
- **Fail criteria:** No rate limiting is implemented at all, or rate limiting is implemented with a single fixed limit regardless of user role, subscription tier, or trust level.
- **Skip (N/A) when:** Project is a purely static site with no API routes, or project is in early development with no subscription/role concept yet established.
- **Detail on fail:** `"Rate limiting is absent or uses a single global limit regardless of user role. Premium users cannot be given higher limits, and abuse is not differentiated from normal use."` (Note whether rate limiting is absent entirely or present but untired.)
- **Remediation:** Implement tiered rate limits based on the user's subscription plan or role.

  ```typescript
  // lib/rate-limit.ts
  import { Ratelimit } from '@upstash/ratelimit';

  const limits = {
    free: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(50, '1 h') }),
    pro: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(500, '1 h') }),
    admin: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(5000, '1 h') }),
  };

  export async function applyRateLimit(userId: string, plan: 'free' | 'pro' | 'admin') {
    const { success } = await limits[plan].limit(userId);
    return success;
  }
  ```

- **Cross-reference:** For related patterns and deeper analysis, see the corresponding checks in other AuditBuffet audits covering this domain.

---

## External references

- cwe CWE-284
- owasp A01
- nist AC-6

Taxons: access-control, cost-efficiency

HTML version: https://auditbuffet.com/patterns/ab-002271
