Rails: How to implement protect_from_forgery in Rails API mode
Here's what the issue was: Rails 5, when in API mode, logically doesn't include the Cookie middleware. Without it, there's no Session key
stored in a Cookie to be used when validating the token I passed with my form.
Somewhat confusingly, changing things in config/initializers/session_store.rb
had no effect.
I eventually found the answer to that problem here: Adding cookie session store back to Rails API app, which led me here: https://github.com/rails/rails/pull/28009/files which mentioned exactly the lines I needed to add to application.rb to get working Cookies back:
config.session_store :cookie_store, key: "_YOUR_APP_session_#{Rails.env}"config.middleware.use ActionDispatch::Cookies # Required for all session managementconfig.middleware.use ActionDispatch::Session::CookieStore, config.session_options
Those three lines coupled with:
class FooController < ApplicationController include ActionController::RequestForgeryProtection protect_from_forgery with: :exception, unless: -> { request.format.json? } ...
And of course a form generated through the proper helpers:
form_tag(FOO_CREATE_path, method: :post) ...
Got me a CSRF protected form in the middle of my Rails API app.
If you're using Rails 5 API mode, you do not use protect_from_forgery
or include <%= csrf_meta_tags %>
in any view since your API is 'stateless'. If you were going to use full Rails (not API mode) while ALSO using it as a REST API for other apps/clients, then you could do something like this:
protect_from_forgery unless: -> { request.format.json? }
So that protect_from_forgery
would be called when appropriate. But I see ActionController::API
in your code so it appears you're using API mode in which case you'd remove the method from your application controller altogether
No need of protect_from_forgery for AJAX calls and apis.
If you want to disable it for some action then
protect_from_forgery except: ['action_name']