Scenario
User is entering a large amount of data to a form and their session expires. The user is redirected to login and loses all of the unsaved data.
Solution
Detect that the session has expired and in a modal dialog, allow them to log back in. Upon successful login, change the CSRF token to the new sessions token and instruct the user to try their request again.
Changes
Changed the SessionsController to allow JSON requests and to return the new token like this:
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message!(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_to do |format|
format.html { respond_with resource, location: after_sign_in_path_for(resource) }
format.json { render json: {csrfToken: form_authenticity_token}, status: :created }
end
end
Implemented a modal dialog (a react-modal-dialog) to be exact, that successfully authenticates the user and returns a new CSRF token. We change the CSRF token via this JQuery:
$('meta[name=csrf-token]').attr('content', data.csrfToken);
Problem
The CSRF token is updated but subsequent ajax calls trigger this warning on the server which kills the users session (as expected in Rails):
[BusinessesController] - Can't verify CSRF token authenticity
Technology
- Rails 4
- JQuery
- Devise 4.1
- ReactJS
Things I've tried
- This suggestion to inject the token manually into the header and not rely on Rails JQuery to handle this.
- This suggestion to inject the CSRF token as part of the payload's body
I can get this to work when I implemented this code as per a suggestion in my Application Controller:
before_filter :verified_request?
def verified_request?
form_authenticity_token == params[request_forgery_protection_token]
puts "**********Here we are expected token: #{form_authenticity_token} ****"
if request.content_type == "application/json"
true
else
super()
end
end
The concern is that this completely disables CSRF checking for API requests. Interestingly also, while running the above code, it appears every page changes the token, which was not my understanding of the token at all. I thought the token was unique per session is this wrong? If this is how the token is expected to work then please point me in the direction of how to solve the initial problem.
Any guidance would be greatly appreciated.