How do you handle CSRF / anti-forgery for a SPA calling an ASP.NET Core API?
Quick Answer
If the SPA authenticates with a bearer token in a header (not a cookie), classic CSRF doesn't apply — the browser doesn't attach the token automatically. If the SPA uses cookie auth, you need anti-forgery: the API issues a token (endpoint or cookie), the SPA reads it and sends it in a header on unsafe requests, and the API validates it. Also set SameSite=Lax/Strict as defence in depth.
It comes down to how the SPA authenticates. If it sends a JWT in the Authorization header, CSRF isn't a concern, because an attacking site can't make the browser attach that header — the browser only auto-sends cookies. If the SPA relies on an auth cookie, then I do need anti-forgery: the API hands the SPA a token, usually via a readable cookie plus an endpoint, and the SPA sends it back in a custom header like X-XSRF-TOKEN on POSTs, which the API validates. On top of either approach I set the auth cookie to SameSite and keep CORS strict.
- Token-in-header auth (JWT): no anti-forgery token needed. Store the token in memory, not
localStorage(XSS), and lock down CORS. - Cookie auth SPA: configure
AddAntiforgery(o => o.HeaderName = "X-XSRF-TOKEN"); expose the token via a minimal endpoint that also sets a readableXSRF-TOKENcookie; the SPA (Angular does this by default) echoes it in the header; protect endpoints with[AutoValidateAntiforgeryToken]. - The BFF (backend-for-frontend) pattern keeps tokens server-side in a cookie and centralises this.