DEV Community

Rishi
Rishi

Posted on

CSRF in the Modern Era: Do you actually need tokens in a decoupled React/Node app?

CSRF in the Modern Era: Do you actually need tokens in a decoupled React/Node app?

For years, the Cross-Site Request Forgery (CSRF) token was the gold standard of web security. Every tutorial told you the same thing: if you have a form, you need a hidden _csrf token.

But as the web shifted from monolithic PHP or Rails apps to decoupled architectures—think a React/Vue frontend talking to a Node/Python API—the conversation changed. With the rise of SameSite cookie attributes and the decline of traditional session cookies, many developers are asking: Is the CSRF token a relic of the past?

The short answer: It depends on how you handle your cookies.


What is CSRF anyway? (The Quick Refresh)

CSRF is an attack that tricks a victim's browser into performing an unwanted action on a different website where the victim is currently authenticated.

Imagine you are logged into your-bank.com. You then visit a malicious site that has a hidden form:
<form action="https://your-bank.com/transfer" method="POST">.
As soon as you land on the page, the form submits. Because your browser automatically attaches your session cookies to requests sent to your-bank.com, the bank thinks you initiated the transfer.


The "Modern" Shield: SameSite Cookies

The reason many claim CSRF is "dead" is the widespread adoption of the SameSite cookie attribute. This tells the browser whether to send cookies with cross-site requests.

  • SameSite=Strict: Cookies are only sent if the request originates from the same site where the cookie was set.
  • SameSite=Lax: (The modern browser default) Cookies are withheld on cross-site subrequests (like images or frames) but sent when a user navigates to the URL (like clicking a link).

If all modern browsers use SameSite=Lax by default, why bother with tokens? Because "Lax" still allows cookies to be sent on top-level GET requests. While GET requests should be idempotent (read-only), a poorly designed API that allows state changes via GET remains vulnerable. Furthermore, older browsers don't support SameSite, leaving those users exposed.


Decoupled Apps: JWTs vs. Cookies

In a React/Node environment, your vulnerability depends entirely on your Authentication Strategy.

Scenario A: You use Cookies (The Risk)

If your Node.js API sends a Set-Cookie header to store a session ID or a JWT in the browser's cookie storage, you are vulnerable to CSRF. Even with a decoupled React frontend, the browser will try to attach that cookie to any request made to your API domain.

  • Verdict: You DO still need CSRF protection (tokens or Double Submit Cookies).

Scenario B: You use LocalStorage/SessionStorage (The Trade-off)

If your React app stores a JWT in localStorage and manually attaches it to the Authorization: Bearer <token> header, you are immune to CSRF. Browsers do not automatically attach headers; they only automatically attach cookies.

  • The Catch: While you solved CSRF, you opened the door to XSS (Cross-Site Scripting). If an attacker runs a malicious script on your page, they can steal that token from localStorage instantly.
  • Verdict: You don't need CSRF tokens, but your security risk has simply shifted elsewhere.

The Modern Solution: The "Double Submit Cookie"

If you want the security of HttpOnly cookies (to prevent XSS) but don't want the overhead of managing CSRF tokens in a database on the server, the Double Submit Cookie pattern is the industry favorite for React/Node apps.

  1. When the user logs in, the server sends a random string in a non-HttpOnly cookie (e.g., csrf-token).
  2. The React app reads this cookie using JavaScript.
  3. For every "state-changing" request (POST/PUT/DELETE), React sends that string back in a custom HTTP header (e.g., X-XSRF-TOKEN).
  4. The server compares the cookie value with the header value. An attacker can't do this because they can't read your cookies from a different domain (thanks to the Same-Origin Policy).

The Checklist

Do you need CSRF tokens in your React/Node app?

  • YES if you use Cookies for authentication (even with SameSite=Lax).
  • NO if you use Bearer Tokens stored in localStorage (but be careful of XSS!).
  • NO if your API is strictly consumed by non-browser clients (Mobile apps, IoT).
  • RECOMMENDED if you want "Defense in Depth" to protect users on older browsers.

Top comments (0)