This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the javascript category.
Last Updated: 2024-11-21
I was given the following JavaScript code to see what files were being downloaded:
const payload = new URLSearchParams({
name: item.dataset.name,
original_item_id: item.dataset.originalItemId,
original_item_type: item.dataset.originalItemType
})
fetch("/track_file_download", {
method: "POST",
body: payload
}).then(() => {
item.innerText = item.innerText + " - Accessed"
item.classList.add("tracked-download-box")
})
This led to a preponderance of CSRF errors in the backend of the Rails web server.
ActionController::InvalidAuthenticityToken
This happened even though the Rails server supposedly made allowance for JSON requests not having this token:
# This contains a proximate micro-bug
protect_from_forgery with: :exception, unless: -> { request.format.json? }
The proximate, and dumb issue, was that the request format was not actually JSON. It
was just JavaScript - and that difference matters. The fix is to add the
appropriate Content-Type
headers.
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data) // body data type must match "Content-Type" header
The bigger picture is that we might want to ensure the CSRF token gets passed with my
JavaScript requests. That would obviate the need to disable the
protect_from_forgery
protections for certain request types.
// the fix
fetch("/track_file_download.json", {
method: "POST",
headers: {
"X-CSRF-Token": document.querySelector("meta[name=csrf-token]").content
},
body: payload
}).then(())