This is an educational project, not for production. I wasn't intending to have user logins as part of this.
Can I make POST calls to Django with a CSRF token without having user logins? Can I do this without using jQuery? I'm out of my depth here, and surely conflating some concepts.
For the JavaScript side, I found this redux-csrf package. I'm not sure how to combine it with my POST
action using Axios:
export const addJob = (title, hourly, tax) => {
console.log("Trying to addJob: ", title, hourly, tax)
return (dispatch) => {
dispatch(requestData("addJob"));
return axios({
method: 'post',
url: "/api/jobs",
data: {
"title": title,
"hourly_rate": hourly,
"tax_rate": tax
},
responseType: 'json'
})
.then((response) => {
dispatch(receiveData(response.data, "addJob"));
})
.catch((response) => {
dispatch(receiveError(response.data, "addJob"));
})
}
};
On the Django side, I've read this documentation on CSRF, and this on generally working with class based views.
Here is my view so far:
class JobsHandler(View):
def get(self, request):
with open('./data/jobs.json', 'r') as f:
jobs = json.loads(f.read())
return HttpResponse(json.dumps(jobs))
def post(self, request):
with open('./data/jobs.json', 'r') as f:
jobs = json.loads(f.read())
new_job = request.to_dict()
id = new_job['title']
jobs[id] = new_job
with open('./data/jobs.json', 'w') as f:
f.write(json.dumps(jobs, indent=4, separators=(',', ': ')))
return HttpResponse(json.dumps(jobs[id]))
I tried using the csrf_exempt
decorator just to not have to worry about this for now, but that doesn't seem to be how that works.
I've added {% csrf_token %}
to my template.
This is my getCookie
method (stolen from Django docs):
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
I've read that I need to change the Axios CSRF info:
var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");
axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"
Where do I stick the actual token, the value I get from calling getCookie('csrftoken')
?
There are three ways. You can manually include the token in the header of each axios call, you can set axios's
xsrfHeaderName
in each call, or you set a defaultxsrfHeaderName
.1. Adding it manually
Let's say you've got the value of the token stored in a variable called
csrfToken
. Set the headers in your axios call:2. Setting
xsrfHeaderName
in the call:Add this:
Then in your
settings.py
file, add this line:3. Setting default headers[1]
Rather than defining the header in each call, you can set default headers for axios.
In the file where you're importing axios to make the call, add this below your imports:
Then in your
settings.py
file, add this line:EDIT: Apparently it works slightly different with Safari[2]
[1] From Dave Merwin's comment
The confusion:
Django Docs
First, the whole passage from the Django docs that James Evans referenced:
Axios Docs
This is from the Axios docs. It indicates that you set the name of the cookie which contains the
csrftoken
, and the name of the header here:Terms
As indicated in my question, you access cookies with
document.cookie
. The only cookie I have is the CSRF token I put in the Django template. Here is an example:csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU
There are a few concepts being thrown around in those docs that get confusing:
csrftoken
, which is on the left side of the equals sign in the cookie.Things I tried that didn't work: 1, 2