Reputation: 1412
I want to build a rails app with two different protect_from_forgery strategies: one for the web application, and one for the API.
In my application controller I have this line of code: protect_from_forgery with: :exception
in order to prevent CSRF attacks, it works just fine.
In my API namespace, I created an api_controller that inherits from my application controller, and that is the parent class of all the other controllers in the API namespace, and I changed the code above with: protect_from_forgery with: :null_session
.
Sadly, I have an error when trying to make POST request: "Can't verify CSRF token authenticity".
I don't want to skip the verify_authenticity_token method in my API controllers, I just want to have two distinct strategies in my app, so how do I override the protect_from_forgery strategy defined in my application controller ?
Edit: Ok, so I eventually did what I did not want to do in the first place: change the inheritance of my api_controller: it now inherits from ActionController::Base, and no longer from my application controller. It does work now but:
So if anyone has a real way to overwrite this method, I'd appreciate it.
Upvotes: 5
Views: 4765
Reputation: 2096
Late to the party, but something like this can be done:
class YourCustomStrategy
def initialize(controller)
end
def handle_request
end
end
And in your ApplicationController or where you want:
class ApplicationController < ActionController::Base
protect_from_forgery with: YourCustomStrategy
end
Upvotes: 1
Reputation: 530
What if you leave the protect_from_forgery with: :exception
in the application controller but then you put the following in your API controller?
skip_before_action :protect_from_forgery
protect_from_forgery with: :null_session
That way, you still get the standard CSRF attack protection for all controllers in your web application but you also get the null session behavior for your API methods.
Upvotes: 13
Reputation: 22926
I am running an application with a similar structure - Web App + API. I solved the CSRF problem like this:
Code:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception, if: :isWebRequest?
def isWebRequest?
request.subdomains[-1] != 'api'
end
end
Upvotes: 6