Building simple user authentication with React and Django but have only got register coded so far. I have tried getting this to work for hours and am getting very frustrated.The react side is built and the register page is being run from the django port 8000.
The development server is getting the cookie and setting it perfectly on local host port 8000. I put it in a hidden input field in my register form, then retrieve the cookie using js-cookie perfectly in auth.js (I can see this with console.log). I then send it with axios with the cookie in the header with withCredentials=true. I get the following error:
error
Forbidden (CSRF cookie not set.): /accounts/register
[28/Feb/2024 19:39:57] "POST /accounts/register HTTP/1.1" 403 2869
I have tried various other methods of sending the cookie. I have all the relevant CORS settings set.
views.py
@method_decorator(ensure_csrf_cookie, name='dispatch')
class GetCSRFToken(APIView):
permission_classes = (permissions.AllowAny, )
def get(self, request, format=None):
return Response({ 'success': 'CSRF cookie set'})
auth.js
import axios from 'axios';
import {
REGISTER_SUCCESS,
REGISTER_FAIL
} from './types';
import Cookies from 'js-cookie'
export const register = (username, password, re_password) => async dispatch => {
const config = {
withCredentials: true,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRFToken': Cookies.get('csrftoken')
}
};
const body = JSON.stringify({ username, password, re_password });
try {
const res = await axios.post(`${process.env.REACT_APP_API_URL}/accounts/register`, body, config);
if (res.data.error) {
dispatch({
type: REGISTER_FAIL
});
} else {
dispatch({
type: REGISTER_SUCCESS
})
}
} catch (err) {
dispatch({
type: REGISTER_FAIL
});
}
}
CSRFToken.js (get csrf token from here. This works)
import React, { useState, useEffect} from 'react'
import axios from 'axios'
const CSRFToken = () => {
const [csrftoken, setcsrftoken] = useState('');
const getCookie = (name) => {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
let cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(`${process.env.REACT_APP_API_URL}/accounts/csrf_cookie`)
setcsrftoken(getCookie('csrftoken'));
} catch (err) {
console.log("error");
}
}
fetchData();
}, []);
return (
<input type="hidden" name="csrfmiddlewaretoken" value={csrftoken} />
);
}
export default CSRFToken
2
Answers
I solved the issue. It was my fault. In my urls I had this:
The catch all url pattern meant for rendering my frontend after build was catching the post requests because of a url mismatch. This was causing me to not realize the url mismatch error as I was getting a 403 Forbidden, and the error included the faulty path which I interpreted as the correct path.
Axios configuration with default values for Cross-Site Request Forgery (XSRF) protection, you can set the xsrfHeaderName and xsrfCookieName properties. These properties specify the names of the HTTP header and cookie to be used for transmitting the Cross-Site Request Forgery token.