-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set up Rails CSRF to play nice with Axios default CSRF behavior #96
Conversation
@@ -11,6 +11,10 @@ module Controller | |||
InertiaRails.share(errors: session[:inertia_errors]) if session[:inertia_errors].present? | |||
end | |||
helper ::InertiaRails::Helper | |||
|
|||
after_action do | |||
cookies['XSRF-TOKEN'] = form_authenticity_token unless request.inertia? || !protect_against_forgery? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -89,6 +90,10 @@ def force_refresh(request) | |||
request.flash.keep | |||
Rack::Response.new('', 409, {'X-Inertia-Location' => request.original_url}).finish | |||
end | |||
|
|||
def copy_xsrf_to_csrf! | |||
@env['HTTP_X_CSRF_TOKEN'] = @env['HTTP_X_XSRF_TOKEN'] if @env['HTTP_X_XSRF_TOKEN'] && inertia_request? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes basically translate Axios's CSRF defaults into Rails's CSRF defaults, and only for Inertia requests
@@ -96,4 +96,40 @@ | |||
|
|||
it { is_expected.to eq 302 } | |||
end | |||
|
|||
describe 'CSRF' do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I set out to actually test the entire CSRF flow. I wanted:
- A test showing that an
X-CSRF-Token
header passes CSRF (essentially verifying Rails default behavior) - A failing test showing that an
X-XSRF-Token
(like Axios will send) fails CSRF - Write the code that translates Axios to Rails
- See that red test turn a sweet green
Turns out that's a nontrivial thing to do! RSpec request tests don't give you access to a session before a request, so it's really difficult to do something like mocking out a form_authenticity_token.
System tests are better suited for testing stateful session based workflows, but the amount of setup required for that did not feel worth it here.
I learned a lot about Rails's CSRF internals along the way!
@@ -0,0 +1,11 @@ | |||
module HelperModule | |||
def with_forgery_protection |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted this for my theoretical full CSRF testing as described above. Still somewhat useful to verify that we only add the XSRF-Token cookie on requests with forgery protection.
It's an excellent feature that enables quick setup of Inertia client-side following the website https://inertiajs.com/client-side-setup |
Resolves #71
More discussion there and #72