HIGH api rate abuseadonisjsopenid connect

Api Rate Abuse in Adonisjs with Openid Connect

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

Rate abuse in AdonisJS when OpenID Connect (OIDC) is used for authentication can occur when protections around authenticated endpoints are weaker than for unauthenticated ones. Even after an OIDC access token is validated, an authenticated identity can be leveraged to hammer protected routes without effective per-identity rate limits. This exposes issues such as missing or misconfigured per-user throttling, weak sliding-window enforcement, and reliance only on global limits that do not account for authenticated identity.

In AdonisJS, a typical OIDC setup uses an auth provider (e.g., Auth0, Okta, or a custom OIDC provider) and an authentication guard that verifies the access token and attaches a user to the authentication context. If routes rely solely on the global rate limiter (e.g., a simple IP-based or fixed-window limiter) and do not scope limits to the authenticated subject (sub) or client_id, an attacker with a valid token can repeatedly call high-cost endpoints while staying under IP-level thresholds. This is especially risky for token-introspection/userinfo endpoints, token refresh flows, or any route that performs database writes tied to the authenticated subject.

Attack patterns enabled by this combination include token replay from multiple source IPs (using the same valid token from a compromised session), credential stuffing against user-specific endpoints (e.g., /me/profile) where protections are lighter than for login, and exploitation of costly operations such as email resend or MFA challenges that may not enforce per-identity throttling. Because OIDC tokens often carry scopes and claims, an attacker might also escalate by targeting routes that require specific scopes while the global limiter does not differentiate by scope or role.

Concrete risk indicators include endpoints that accept authenticated requests but lack route-specific middleware for throttling, inconsistent limit configurations across public and authenticated routes, and logs showing many requests with the same subject or token value across a short time window. OWASP API Top 10 categories such as Broken Object Level Authorization (BOLA) and Security Misconfiguration intersect here when identity-aware protections are missing or inconsistently applied.

To detect this using a black-box scanner like middleBrick, scans compare authenticated versus unauthenticated behavior for the same endpoint, checking whether rate limiting changes meaningfully after successful OIDC authentication. Findings highlight whether per-identity throttling exists, whether limits vary by scope/role, and whether high-risk operations such as token refresh or user info retrieval are adequately constrained.

Openid Connect-Specific Remediation in Adonisjs — concrete code fixes

Remediation centers on scoping rate limits to the authenticated subject or token identity and ensuring that high-risk flows (token refresh, userinfo, consent) have stricter, per-identity limits. Below are concrete, syntactically correct examples for AdonisJS that you can adapt to your OIDC provider and route design.

1. Configure per-subject rate limiter

Create a custom rate limiter that uses the authenticated user’s subject (sub) from the OIDC token. This ensures that each authenticated identity has its own quota.

// start/handlers/rate-limiter.ts
import { Exception } from '@poppinss/utils'
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'

export default class RateLimiter {
  public async handle({ auth, response, next }: HttpContextContract) {
    const user = auth.getUserOrFail()
    // Use subject (sub) from OIDC claims when available
    const key = user.sub || 'anonymous'
    const limit = 300        // requests
    const windowMs = 60_000  // per minute
    const bucketKey = `rl:oidc:${key}`

    const previous = await use('Adonis/Addons/Limiter').consumed(bucketKey)
    if (previous >= limit) {
      response.status(429).send({ error: 'rate_limit_exceeded', message: 'Too many requests for your identity' })
      return
    }
    await use('Adonis/Addons/Limiter').consume(bucketKey, 1)
    await next()
  }
}

2. Apply per-identity limiter to authenticated routes

Attach the limiter only to authenticated routes or specific high-risk groups (userinfo, refresh, profile updates). Combine with route-level guards to avoid applying it to public endpoints where IP-based limits suffice.

// routes.ts
import Route from '@ioc:Adonis/Core/Route'
import RateLimiter from 'App/Handlers/RateLimiter'

Route.group(() => {
  Route.get('/me', async ({ auth, response }) => {
    const user = auth.getUserOrFail()
    return response.ok({ subject: user.sub, email: user.email })
  }).middleware(['auth:oidc', RateLimiter])

  Route.post('/profile', async ({ auth, request, response }) => {
    const user = auth.getUserOrFail()
    // handle profile updates
    return response.ok({ updated: true })
  }).middleware(['auth:oidc', RateLimiter])

  // High-risk token operations
  Route.post('/oauth/token/refresh', async ({ auth, response }) => {
    // token refresh logic with OIDC
    return response.ok({ access_token: '...' })
  }).middleware(['auth:oidc', RateLimiter])
})
  .prefix('/api')

3. OIDC-aware middleware to enrich context

Ensure your authentication middleware extracts and attaches OIDC claims so the rate limiter can reliably identify subjects and scopes. Example using an OIDC introspection strategy.

// start/kernel.ts
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
import { Exception } from '@poppinss/utils'

export const guards = {
  oidc: {
    driver: 'jwt',
    provider: 'oidc-jwt',
    tokenProvider: 'adonis-local',
    // Assume validateToken returns { sub, scope, email, ...claims }
    handleValidToken: async (ctx: HttpContextContract, tokenPayload: any) => {
      ctx.auth.loginUsingId(tokenPayload.sub, { token: { scope: tokenPayload.scope } })
    },
    handleInvalidToken: (ctx: HttpContextContract) => {
      throw new Exception('Invalid token', 401, 'E_INVALID_TOKEN')
    }
  }
}

4. Differentiate limits by scope or operation risk

For endpoints with higher risk (token refresh, userinfo), use tighter limits scoped to identity and, where feasible, to operation type. Avoid relying only on IP-based or global fixed-window limits when authenticated flows are involved.

// routes.ts with operation-specific limits
Route.post('/oauth/token/refresh', handler).middleware(['auth:oidc', 'RateLimiter:strict'])

// handlers/RateLimiterStrict.ts with tighter limits
export default class RateLimiterStrict {
  public async handle({ auth, response, next }: HttpContextContract) {
    const user = auth.getUserOrFail()
    const key = `rl:oidc:strict:${user.sub}`
    const limit = 10      // stricter for sensitive flows
    const windowMs = 60_000
    // implement consume/check as above
    await next()
  }
}

5. Monitoring and observability

Log identity-based usage for audit and anomaly detection. Correlate request subject, route, and timestamps to spot patterns consistent with abuse while respecting privacy and data minimization principles.

These steps ensure that OIDC authentication in AdonisJS strengthens, rather than weakens, rate abuse protections by tying limits to authenticated identities and high-risk operations.

Frequently Asked Questions

Does middleBrick test for rate abuse when OpenID Connect is used in AdonisJS?
Yes. middleBrick runs parallel checks including Rate Limiting and Authentication. When you scan an endpoint that uses OpenID Connect, it compares authenticated versus unauthenticated behavior to determine whether per-identity rate limits are present and effective.
Can I see which endpoints are most at risk for API rate abuse in the middleBrick dashboard?
Yes. The dashboard provides per-category breakdowns and prioritized findings with severity and remediation guidance, including indicators specific to authentication and rate limiting configurations.