What is the difference between Spring Security's CSRF protection and CORS, and when should each be enabled/disabled?
Quick Answer
CSRF (Cross-Site Request Forgery) protection defends against a malicious site tricking a logged-in user's browser into submitting a state-changing request to your application using the user's own existing session/cookies — relevant specifically for cookie/session-based authentication, since the browser automatically attaches cookies to any request regardless of origin. CORS controls which cross-origin JavaScript requests a browser will even allow to be made/read at all. A stateless, token-based (JWT) API typically disables CSRF protection (since there's no ambient session cookie to forge a request with) but still needs CORS configured if it's called from browser-based JavaScript on a different origin.
Detailed Answer
These two are frequently confused because both are "cross-origin"-related browser security concerns, but they defend against different threats and are largely independent settings.
CSRF (Cross-Site Request Forgery) protects against a scenario where a user is logged into your application (holding a valid session cookie), then visits a different, malicious site while still logged in. That malicious site can craft a form or script that submits a request to your application's endpoints — and the browser will automatically attach the user's existing session cookie to that request, since cookies are sent based on the target domain, not which page initiated the request. Without protection, your server would see what looks like a legitimate, authenticated request and act on it (e.g., transferring funds, changing an email address) — even though the user never intended to make that request.
Spring Security's CSRF protection defends against this by requiring a CSRF token (unpredictable to the malicious site, since it can't read cross-origin response content) to be included in state-changing requests (POST/PUT/DELETE), in addition to whatever cookie is automatically attached:
http.csrf(Customizer.withDefaults()); // enabled by default for session-based apps
CORS (Cross-Origin Resource Sharing) is a different browser mechanism: it controls whether a browser will even allow a cross-origin JavaScript request to be made and its response read by the calling page's script at all — it's about which origins are permitted to interact with your API via fetch/XMLHttpRequest, not about forged form submissions using ambient cookies.
When to enable/disable each:
- Session/cookie-based authentication (a traditional server-rendered app, or an SPA using cookie-based sessions): CSRF protection should stay enabled — cookies are exactly the ambient-credential mechanism CSRF attacks exploit.
- Stateless, token-based authentication (JWT in an
Authorizationheader): CSRF protection is typically disabled, because the attack doesn't apply the same way — a malicious site can't make the victim's browser automatically attach anAuthorizationheader the way it automatically attaches cookies; the token would have to be explicitly known/set by the malicious page's own JavaScript, which cross-origin restrictions (and CORS) already prevent from reading your application's stored token in the first place. - CORS needs to be configured correctly (specific allowed origins, not
*, especially if credentials are involved) regardless of the authentication style, any time the API is genuinely called from browser-based JavaScript running on a different origin than the API itself.
Common mistake: disabling CSRF protection reflexively for any API "because it's an API," without confirming the API is actually stateless — if session/cookie-based auth is still in play anywhere, disabling CSRF removes a real protection against a real attack.