HIGH api rate abuseaspnetbearer tokens

Api Rate Abuse in Aspnet with Bearer Tokens

Api Rate Abuse in Aspnet with Bearer Tokens — how this specific combination creates or exposes the vulnerability

Rate abuse in ASP.NET APIs that rely on Bearer tokens occurs when an attacker can make a high volume of authenticated requests without meaningful enforcement of per-identity or per-client limits. Because Bearer tokens are typically validated by the framework before business logic runs, protections that exist at the network or edge may not apply, and application-level rate limiting must explicitly consider token identity.

In ASP.NET Core, if you only enable rate limiting via IP-based policies or global middleware without scoping limits to the token or user ID, a single compromised or shared token can be used to saturate backend resources. For example, an attacker who steals or guesses a valid Bearer token can send thousands of requests per minute to endpoints like /api/values, bypassing protections that only inspect origin IPs.

Consider the following realistic token validation setup in ASP.NET Core that does not scope limits by token or user identity. In this configuration, the policy applies globally without differentiating requests by the claims extracted from the Bearer token:

// Program.cs (incomplete example — missing per-token rate limiting)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://auth.example.com";
        options.Audience = "api1";
    });
builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitioningRateLimiter.Create(_ => RateLimitPartition.GetNoLimiter());
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();

Because the global limiter does not partition by token or user claims, the effective protection is weak: an attacker with a valid token can exhaust server capacity while appearing as a single client from a permissible IP range. This becomes especially dangerous when endpoints perform expensive operations or open downstream connections, enabling denial-of-service via token misuse rather than network flooding.

OWASP API Security Top 10 highlights this as a form of BFLA (Business Logic Flaws and Abuse), where legitimate credentials are abused to degrade availability. Additionally, frameworks like ASP.NET Core expose claims such as ClaimTypes.NameIdentifier or sub from validated JWTs, which should be used to enforce per-identity limits. Without partitioning rate limits by token or user ID, defenses remain coarse and leaky.

To detect such issues, scanners look for missing EnableRateLimiting or AddRateLimiter configurations that incorporate token-derived identifiers, and they flag endpoints where authentication is present but rate partitions do not reference claims like sub or nameid. Proper remediation requires tying rate limit keys to the authenticated principal derived from the Bearer token, ensuring that abuse is constrained at the identity level rather than only by IP or global thresholds.

Bearer Tokens-Specific Remediation in Aspnet — concrete code fixes

To remediate rate abuse in ASP.NET when using Bearer tokens, you must incorporate token-derived claims into your rate-limiting partitions. The following example shows a complete, minimal setup that authenticates with JWT Bearer tokens and applies rate limits per user identifier extracted from the token.

// Program.cs — secure per-token rate limiting
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.RateLimiting;
using System.IdentityModel.Tokens.Jwt;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

// 1) Validate Bearer tokens
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://auth.example.com";
        options.Audience = "api1";
        options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true
        };
    });

// 2) Configure rate limiter keyed by user identifier from the token
builder.Services.AddRateLimiter(options =>
{
    options.GlobalLimiter = PartitioningRateLimiter.Create(context =>
    {
        // Extract user identifier from validated claims
        var user = context.User;
        if (user.Identity?.IsAuthenticated == true)
        {
            // Prefer "sub" or NameIdentifier claim present in most JWTs
            var userId = user.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
                         ?? user.FindFirst("sub")?.Value
                         ?? user.Identity.Name;
            if (!string.IsNullOrEmpty(userId))
            {
                return RateLimitPartition.GetTokenBucketLimiter(userId, _ => new TokenBucketRateLimiterOptions
                {
                    TokenLimit = 100,
                    QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                    QueueLimit = 10,
                    ReplenishmentPeriod = TimeSpan.FromSeconds(10),
                    PermitLimit = 20
                });
            }
        }
        // Fallback to a safe default limiter
        return RateLimitPartition.GetNoLimiter();
    });
    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.UseRateLimiter();

app.MapGet("/api/values", () => "Secure data")
   .RequireAuthorization();

app.Run();

In this code, the rate limiter partitions buckets by a user identifier taken from the Bearer token claims (NameIdentifier or sub). This ensures that even if a token is leaked, abuse is limited to the capacity defined per token rather than globally. You can adjust TokenLimit, ReplenishmentPeriod, and PermitLimit to match your service’s expected load and resilience targets.

For production, you should also validate token audiences and issuers strictly and consider distributed rate limiting if you run multiple service instances. The same principles apply if you use reference tokens or opaque tokens: map the token to a stable identity (e.g., via introspection or a local mapping) and use that identity as the rate limit key.

The following minimal Bearer token request example demonstrates how a client would call the protected endpoint once rate limiting is correctly configured:

// Example request using curl with a Bearer token
// Replace {your_token} with a valid JWT issued by your auth server
curl -X GET "https://api.example.com/api/values" \
     -H "Authorization: Bearer {your_token}"

By anchoring rate limits to the authenticated identity derived from the Bearer token, you reduce the risk of token-based rate abuse and align with patterns recommended by the OWASP API Security Top 10 and common zero-trust practices.

Frequently Asked Questions

What claims should I use to identify users for rate limiting in ASP.NET with Bearer tokens?
Use stable, non-rewritable claims present in your JWTs. Commonly, 'sub' (subject) or NameIdentifier are ideal. Avoid relying on email or username if they can change, and always validate issuer and audience before using claims.
Can I rely on IP-based rate limits alone when using Bearer tokens in ASP.NET?
No. IP-based limits are easily bypassed when an attacker has a valid Bearer token, because requests originate from permitted IPs. You must scope limits to the token or user identity to prevent token-specific abuse.