How do you secure a Web API?
Quick Answer
Layered: HTTPS everywhere; authenticate every request (JWT bearer, OAuth2, or API keys for service-to-service); authorize per endpoint with policies; validate and bind to DTOs to stop over-posting and injection; add rate limiting; lock down CORS to known origins; return generic errors (no stack traces); and keep dependencies patched.
I think about it in layers. Transport: HTTPS and HSTS. Authentication: every request carries a credential — JWT bearer for users, client-credentials OAuth or signed keys for other services — and I validate issuer, audience and expiry, not just the signature. Authorization: policies per endpoint, and resource-level checks so a user can't fetch someone else's record by changing the id. Input: validate, bind to DTOs not entities to prevent over-posting, and let EF or parameters handle SQL so there's no injection. Then rate limiting to blunt abuse, a strict CORS allow-list, generic ProblemDetails errors with no stack traces, secrets in a vault, and keeping packages patched.
- Transport —
UseHttpsRedirection+ HSTS; TLS terminated at the edge is fine. - AuthN — JWT bearer for users/SPAs, client-credentials OAuth or signed API keys for machine callers. Validate issuer, audience, lifetime, signature.
- AuthZ —
[Authorize(Policy = ...)], resource-based checks for “can this user touch this record”. - Input — model validation, DTOs (not entities), parameterised queries / EF (no string-concatenated SQL), size limits on bodies and uploads.
- Abuse — rate limiting (
AddRateLimiter), request throttling, and idempotency keys on unsafe operations. - CORS — an explicit allow-list of origins; never
AllowAnyOriginwith credentials. - Output —
ProblemDetailserror bodies with no internal detail; security headers. - Ops — secrets in a vault, logging without PII/tokens, dependency scanning.