ASP.NET Core  

CSRF for Beginners: Understanding Security Warnings in ASP.NET Core APIs

Introduction

When you start building ASP.NET Core Web APIs, security tools like Coverity, SonarQube, or Fortify may suddenly report warnings such as “Cross-Site Request Forgery (CSRF) vulnerability detected”. For beginners, this can be confusing and even alarming — especially when your API already uses JWT authenticationand works perfectly fine.

In this article we are going to see what CSRF really is, why these warnings appear, and when you actually need to worry about them, using simple language and practical examples.

What is CSRF (in simple terms) ?

Here is the simplest way to visualize a CSRF attack from start to finish:

  1. You log into MyBank.com. Your browser now holds a Session Cookie (your digital "ID Badge"). As long as you don't log out, your browser will show this badge to the bank every time they talk.

  2. Without logging out of your bank, you open a new tab and visit a Shady-Site.com (the "Bad" website).

  3. 3. Inside that shady website, there is a hidden line of code that looks like this:
    Transfer $500 to Hacker

  4. The moment you land on the shady site, it forces your browser to send that transfer command to MyBank.com.

  5. Your browser thinks: "Oh, a request for MyBank! I’ll attach the ID Badge (Cookie) so they know who it is."

  6. Crucial Point: Your browser does this automatically without asking you.

  7. MyBank.com receives the request. It sees your valid ID Badge attached. It thinks, "This must be from the user," and it processes the transfer.

CSRF attacks work because browsers automatically send cookies. CSRF is like a forged signature.

Example:

Consider this API endpoint:

[HttpPost]
public async Task<IActionResult> SubmitNewOptOut([FromBody] OptOutViewModel model)
{
    if (!ModelState.IsValid)
        return BadRequest("Invalid data");

    await _dbService.AddNewOptOut(model);
    return Accepted();
}

This endpoint:

  • Accepts a POST request

  • Updates the database

  • Looks completely normal

However, a security scanner may still flag it as CSRF vulnerable. Why ? Static analysis tools look at patterns, not runtime behavior.

They see:

  • A POST method

  • Data modification

  • No visible CSRF token validation

So they assume: “This request might be authenticated using cookies and needs CSRF protection.”

They do not know how your authentication is actually implemented.

How Modern Angular + ASP.NET Core Apps Authenticate

When you useJWT tokens (common in React, Angular, and ASP.NET Core), the rules change. This setup is naturally much safer against CSRF. Here is how it works:

1. The Token is Manual

Unlike cookies, which are "sticky" and stay in the browser’s pocket, a JWT Bearer Token is just a piece of text your code holds. The browser never sends it to the server unless your JavaScript code (Angular/React) specifically attaches it.

2. The Bad Website is Powerless

If you visit a "bad" website while logged in with a JWT:

  • The bad website tries to send a command to your bank/API.

  • The browser does not automatically attach the JWT token.

  • The bad website cannot "steal" the token from your React app because browsers have security walls (Same-Origin Policy) that prevent one site from reading another site's data.

3. The Server Rejects the Forgery

When the fake request arrives at your API:

  • The API looks for the Authorization: Bearer <token> header.

  • Since the browser didn't add it automatically, the header is missing.

  • The API says, "I don't know who this is," and blocks the request.

CSRF protection is usually unnecessary for JWT APIs because authentication is manual, not automatic. Since browsers do not automatically attach Bearer tokens to requests, a forged request from a malicious site will lack the requiredAuthorization header. Your API will simply see the missing token and reject the request, making the CSRF attack impossible.

What You Can Do About It

Option 1: Explicitly Ignore CSRF for API Endpoints

[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> SubmitNewOptOut(...)
{
    ...
}

This clearly documents that CSRF protection is intentionally not used.

Option 2: Document the Security Decision

Add a note in your security documentation explaining:

  • JWT Bearer authentication is used

  • No cookie-based authentication exists

  • CSRF protection is not applicable

This is common in enterprise projects.

Conclusion

In this article, we have seen that CSRF is primarily a risk for cookie-based sites, while JWT-based APIs are naturally protected because browsers don't send tokens automatically. By understanding your authentication flow, you can confidently distinguish between real security threats and false positives from static analysis tools.