REST APIs are the backbone of modern applications, powering everything from mobile apps to enterprise integrations. But with this power comes responsibility; if APIs aren’t secure, they become an easy target for attackers.
In this article, we’ll walk through how to build secure REST APIs with ASP.NET Core , covering authentication, authorization, data protection, and real-world code samples .
Step 1: Start with HTTPS Everywhere
APIs must never be exposed over plain HTTP. Use HTTPS to encrypt communication.
In Program.cs
:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseHttpsRedirection(); // Force HTTPS
app.MapControllers();
app.Run();
Step 2: Implement Authentication with JWT
Most secure APIs rely on JWT (JSON Web Tokens) for authentication.
Configure JWT in Program.cs
:
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
Secure Controller with [Authorize]
:
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult GetOrders()
{
return Ok(new { Message = "Secure orders retrieved!" });
}
}
Step 3: Role-Based Authorization
Control who can access what using roles or policies.
[HttpPost]
[Authorize(Roles = "Admin")]
public IActionResult CreateOrder()
{
return Ok("Order created by Admin");
}
For more granular control, use policy-based authorization :
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("RequireManager", policy => policy.RequireRole("Manager"));
});
Step 4: Input Validation & Model Binding
Never trust user input—validate it.
public class OrderModel
{
[Required]
public string Product { get; set; }
[Range(1, 100)]
public int Quantity { get; set; }
}
[HttpPost]
public IActionResult PlaceOrder([FromBody] OrderModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
return Ok("Order placed securely");
}
Step 5: Secure Cookies & Sessions (If Used)
If your API uses cookies (rare, but possible), enforce secure settings :
builder.Services.AddSession(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});
Step 6: Protect Against CSRF
Step 7: Secure Data at Rest & In Transit
var user = await _context.Users
.FirstOrDefaultAsync(u => u.Email == email);
Step 8: Enable Logging & Monitoring
Log authentication failures, suspicious requests, and unusual patterns.
Log.Logger = new LoggerConfiguration()
.WriteTo.File("logs/security.log")
.CreateLogger();
Integrate with Azure Monitor/Application Insights for better visibility.
Step 9: Throttle & Rate Limit
APIs without throttling are prone to DoS attacks. Use AspNetCoreRateLimit
or built-in middleware.
builder.Services.AddRateLimiter(options =>
{
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(
_ => RateLimitPartition.GetFixedWindowLimiter("global", _ =>
new FixedWindowRateLimiterOptions
{
PermitLimit = 100,
Window = TimeSpan.FromMinutes(1)
}));
});
Step 10: Keep Dependencies & Secrets Secure
dotnet user-secrets set "Jwt:Key" "SuperSecretKey123!"
Secure API Checklist
Force HTTPS with redirection.
Use JWT for authentication.
Apply role/policy-based authorization.
Validate all input models.
Use parameterized queries (no raw SQL).
Encrypt sensitive data.
Enable logging & monitoring.
Apply rate limiting.
Store secrets securely.
Keep NuGet packages updated.
Conclusion
Building a REST API in ASP.NET Core is straightforward, but building a secure REST API requires discipline. By applying the techniques in this article—authentication, authorization, validation, encryption, logging, and monitoring you ensure your APIs are resilient against common attacks.
Security isn’t a one-time task. It’s a continuous process of auditing, patching, and improving. Start small, adopt these best practices, and make security part of your team’s development culture.