HIGH api rate abusefeathersjsopenid connect

Api Rate Abuse in Feathersjs with Openid Connect

Api Rate Abuse in Feathersjs with Openid Connect — how this specific combination creates or exposes the vulnerability

Rate abuse in a FeathersJS application using OpenID Connect (OIDC) typically occurs when authentication is present but rate limits are not enforced per authenticated identity or per client. Because OIDC introduces scopes, roles, and subject identifiers that are not present in unauthenticated requests, naive rate limiting can either over-protect public endpoints or under-protect privileged authenticated paths.

FeathersJS does not apply global rate limits by default. If you add an authentication layer (e.g., JWT or OIDC) and then only rate-limit by IP, an attacker who obtains a valid access token can rotate IPs while exhausting the token’s permissions. Conversely, if you rate-limit only after authentication using a simplistic middleware that counts tokens, a single compromised client secret can allow a burst of requests under the same token identity, bypassing IP-based thresholds.

In OIDC flows, tokens contain claims such as sub (subject), scopes, and roles. If rate limiting is applied naively using only these claims without considering context like client_id or key id (kid), an attacker with one valid token can saturate resources for that subject. Additionally, FeathersJS hooks that rely on authenticated params.user may apply business logic without verifying whether the request is within allowed limits, enabling mass enumeration or data scraping through endpoints like /users or /reports.

Real-world attack patterns include token replay within a short window, credential stuffing where each attempt uses a distinct token, and exploitation of public endpoints that inadvertently grant privileged data when accessed repeatedly. For example, an endpoint like /api/reports/:id that does not enforce per-subject rate limits could allow an attacker with a low-privilege token to iterate over IDs rapidly, leading to IDOR-like exposure even when authentication is enforced.

Because FeathersJS services are event-driven and can scale horizontally, in-memory rate limit counters are unreliable. Without a shared store or a mechanism to tie rate limits to OIDC subject and client identifiers, protections can be inconsistent across instances. This inconsistency creates a window where authenticated requests bypass intended throttling, effectively exposing the API to abuse despite the presence of OIDC.

Openid Connect-Specific Remediation in Feathersjs — concrete code fixes

To address rate abuse in FeathersJS with OIDC, combine OIDC-aware identity parsing with a robust rate-limiting strategy that ties limits to subjects and, where relevant, client identifiers. The goal is to enforce limits at the service layer using data that reflects the authenticated context rather than only IP or global counters.

First, ensure your OIDC integration correctly populates params.user so that downstream hooks and services can access claims. Below is a typical OIDC setup using @feathersjs/authentication and @feathersjs/authentication-oauth:

const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
const oauth = require('@feathsjs/authentication-oauth');
const app = require('./app');

app.configure(authentication({
  secret: 'your-secret',
  path: '/authentication',
  service: 'authentication',
  entity: 'user',
  paginate: {
    default: 10,
    max: 50
  }
}));

app.configure(jwt());
app.configure(oauth());

Next, implement a rate-limiting hook that reads the subject and, if available, the client identifier from the token. Use a store like Redis to share state across instances. Here is an example hook that limits requests per subject and per path:

const { GeneralError } = require('@feathersjs/errors');
const Redis = require('ioredis');
const redis = new Redis();

const rateLimit = (options = {}) => {
  const { windowMs = 60_000, max = 100, identifier = (context) => {
    // Prefer subject from OIDC token, fall back to IP
    const user = context.params.user;
    if (user && user.sub) {
      // Optionally include client_id or a token identifier if present
      const client = context.params.auth?.client_id || 'default';
      return `${user.sub}:${client}`;
    }
    return context.params.connection?.remoteAddress || 'unknown';
  } } = options;

  return async (context) => {
    const key = `rl:${identifier(context)}`;
    const current = await redis.incr(key);
    if (current === 1) {
      await redis.expire(key, Math.ceil(windowMs / 1000));
    }
    if (current > max) {
      throw new GeneralError('Rate limit exceeded', { code: 429 });
    }
    return context;
  };
};

// Apply to specific services
app.service('reports').hooks({
  before: {
    all: [rateLimit({ windowMs: 60_000, max: 120 })],
    find: [rateLimit({ windowMs: 60_000, max: 30 })]
  }
});

For OIDC, it is important to scope limits by subject and optionally by client_id or key id (kid) to prevent a single token from monopolizing resources. If your access token includes client_id or a kid, incorporate it into the identifier to further isolate abusive clients without impacting legitimate users sharing the same subject across different clients.

Additionally, differentiate rate limits by HTTP method and path severity. For example, allow more reads on public lists but restrict writes and sensitive queries. FeathersJS hooks make this easy by checking context.method and context.path inside the identifier function. This approach aligns with OWASP API Top 10 protections against excessive data exposure and helps mitigate brute-force and scraping attacks that target authenticated endpoints.

Finally, monitor and adjust thresholds using the dashboard or CLI output. If you use the middleBrick CLI (middlebrick scan <url>) alongside your FeathersJS services, you can correlate detected rate abuse patterns with your configured limits and refine thresholds iteratively. The Pro plan’s continuous monitoring can alert you when request volumes for specific subjects exceed expected baselines, enabling proactive tuning rather than reactive blocking.

Frequently Asked Questions

Why is rate limiting by IP insufficient when using OpenID Connect in FeathersJS?
Because OIDC tokens authenticate users independently of IP. An attacker with a valid token can rotate IPs while exhausting permissions. Rate limits must be tied to the token subject (and optionally client_id) to prevent authenticated abuse.
Can middleBrick scans detect rate abuse patterns in FeathersJS services using OIDC?
middleBrick scans the unauthenticated attack surface and can identify missing rate limiting on authenticated endpoints. It does not fix issues but provides findings with remediation guidance to help you tighten per-subject or per-client limits.