Securing an ASP.NET Core Web API is a critical step in protecting sensitive data and ensuring only trusted clients can interact with your application. In modern software systems, APIs are the backbone of communication, making them a prime target for attackers.

This article outlines practical strategies and code examples for securing your ASP.NET Core Web API applications.

Why Security Matters in APIs?

1. Enforce HTTPS and HSTS

Always ensure encrypted communication between clients and your API.

  
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseHttpsRedirection();
    app.UseHsts();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
  

Prevents man-in-the-middle attacks and secures data in transit.

2. Implement Strong Authentication (JWT)

Authentication ensures only valid users access your API. The most common method is JSON Web Token (JWT) authentication.

Configure JWT Authentication

  
    services.AddAuthentication("Bearer")
    .AddJwtBearer("Bearer", options =>
    {
        options.Authority = "https://your-identity-provider.com"; // IdentityServer / Auth0 / Azure AD
        options.Audience = "your-api";
        options.RequireHttpsMetadata = true;
    });
  

Enable in middleware.

  
    app.UseAuthentication();
app.UseAuthorization();
  

Ensures only authenticated clients can make API calls.

3. Authorization with Roles & Policies

Use role-based or policy-based access control.

  
    [Authorize(Roles = "Admin")]
[HttpGet("admin-data")]
public IActionResult GetAdminData()
{
    return Ok("This endpoint is only for Admins.");
}
  

Policy-based example.

  
    services.AddAuthorization(options =>
{
    options.AddPolicy("RequireHR", policy =>
        policy.RequireClaim("Department", "HR"));
});
  
  
    [Authorize(Policy = "RequireHR")]
public IActionResult GetHRData() => Ok("Only HR staff can access this");
  

Provides fine-grained access control.

4. Validate Input Data

Never trust client input. Use Data Annotations or FluentValidation.

  
    public class RegisterUserDto
{
    [Required, StringLength(50)]
    public string Username { get; set; }

    [Required, EmailAddress]
    public string Email { get; set; }

    [Required, MinLength(8)]
    public string Password { get; set; }
}
  

In your controller.

  
    [HttpPost("register")]
public IActionResult Register([FromBody] RegisterUserDto dto)
{
    if (!ModelState.IsValid) return BadRequest(ModelState);
    return Ok("User registered successfully");
}
  

Prevents SQL injection, XSS, and invalid requests.

5. Protect Against CSRF

  
    services.AddAntiforgery(options => 
{
    options.Cookie.Name = "X-CSRF-TOKEN";
});
  

✅ Protects against cross-site request forgery.

6. Rate Limiting & Throttling

Protect your API from brute force attacks and DoS (Denial of Service) attacks.

Install the AspNetCoreRateLimit NuGet package.

  
    Install-Package AspNetCoreRateLimit
  

Configure in Startup.cs

  
    services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddInMemoryRateLimiting();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
  

appsettings.json

  
    "IpRateLimiting": {
  "EnableEndpointRateLimiting": true,
  "GeneralRules": [
    {
      "Endpoint": "*",
      "Period": "1m",
      "Limit": 30
    }
  ]
}
  

Prevents abuse by limiting requests per user/IP.

7. Secure Secrets with Azure Key Vault

Never hardcode API keys or connection strings.

  
    builder.Configuration.AddAzureKeyVault(
    new Uri("https://your-keyvault.vault.azure.net/"),
    new DefaultAzureCredential());
  

Keeps secrets safe from source code leaks.

8. CORS (Cross-Origin Resource Sharing)

Restrict your API to trusted origins only.

  
    services.AddCors(options =>
{
    options.AddPolicy("AllowTrusted",
        builder => builder.WithOrigins("https://your-frontend.com")
                          .AllowAnyHeader()
                          .AllowAnyMethod());
});
  

Prevents unauthorized domains from consuming your API.

9. Add Security Headers

Protect users against clickjacking, MIME sniffing, and XSS.

  
    app.Use(async (context, next) =>
{
    context.Response.Headers.Add("X-Frame-Options", "DENY");
    context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
    context.Response.Headers.Add("Referrer-Policy", "no-referrer");
    context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'");
    await next();
});
  

Adds an extra layer of defense.

10. Logging & Monitoring

Use structured logging for suspicious activities.

  
    _logger.LogWarning("Unauthorized access attempt from {IP}", HttpContext.Connection.RemoteIpAddress);
  

Integrate with,

Helps detect and respond to attacks in real time.

11. Keep Dependencies Updated

Run

  
    dotnet list package --outdated
  

Use tools like Snyk or OWASP Dependency Check.

Reduces the risk of vulnerable libraries.

12. Security Testing & Threat Modeling

Ensures your API is hardened against real-world attacks.

Final Thoughts

Securing an ASP.NET Core Web API requires layered security. Here’s the checklist:

By applying these best practices, you can build APIs that are not just functional but secure, resilient, and production-ready.