A Rails API that authenticates with a bearer token in a header and sets no cookies generally does not need CSRF tokens, because the forged request has no credential to ride on. If you add cookie sessions, you need protection again. This is reasoning from how the attack works, so confirm it for your design.
How the attack works
The Rails security guide describes cross site request forgery this way: a page on another site can cause a victim's browser to send a request carrying the victim's session cookie, so the target app may act on it as the victim. The browser attaches the cookie automatically. That automatic attachment is the whole attack.
Rails guards against it with a token placed in forms and checked on non GET requests. The guide says new applications enable protect_from_forgery by default.
Where API mode fits
API mode leaves out cookie and session middleware by default, per the Rails API guide. With no cookie to attach, there is nothing for a forged page to piggyback on. Header based credentials, such as a bearer token, are not attached automatically by browsers, which is why token APIs are commonly exempt. The Spring Security documentation makes a similar point: a backend that does not serve browser traffic may disable CSRF protection.
Decision table
| Your API | CSRF tokens needed? |
|---|---|
| Token in header, no cookies, no browser sessions | Generally no |
| Cookie session set by the same app | Yes |
| Mixed: browser app and token clients | Yes for the browser paths |
| Cookies added back to API mode for convenience | Yes, treat as a full app |
Steps to check your own app
- Search the code for cookie and session usage. Look in config for added middleware.
- Check how clients authenticate. If any browser flow relies on a cookie, you are in the cookie row.
- If cookies exist, enable request forgery protection for those controllers and send the token in the X-CSRF-Token header from your JavaScript, as the guide describes for Turbo and custom requests.
- Remember the guide's warning that cross site scripting bypasses CSRF protection, since injected script can read the token.
- Run a scan that sends state changing requests without the token and see what is accepted.
Mistakes that cause real findings
- Turning protection off globally to fix a test, then forgetting it.
- Persisting login in a long lived cookie while calling the app an API.
- Allowing wide CORS together with credentials, which undermines the browser's own protections. Our post on CORS credentials and wildcard rules explains the browser rule.
Try it yourself
Click through it at your own pace, or open it full screen. Look for how the scan treats authenticated, state changing requests.
Safeguard's dependency scanning also flags vulnerable gems in the stack, and a free scan is available.
Quick check
Is CSRF a risk for JWT in the Authorization header?
Usually not, since browsers do not add that header on their own. Storing the token in a cookie changes the answer.
Does Rails enable CSRF protection in API mode?
API mode drops cookie handling by default, so the classic cookie based flow is absent. Verify your own configuration.
Sources
Last reviewed: 19 October 2026.