CSRF Verification failing in local deployment

I had this CSRF issue for multiple months. I gave up initially and I picked it back up because I want to know why this does not work. The main issue is when I add the csrf_protect decorator along with having ‘django.middleware.csrf.CsrfViewMiddleware’ imported, the backend throws a CSRFtoken error. When I do not include the csrf_protect decorator and only have the blanket protection of CsrfViewMiddleware, the api request works without needing the token at all.

Here are my settings relating to CORS and CSRF in my settings file

CORS_ALLOWED_ORIGINS = ['http://localhost:3000', 'http://localhost:3001']
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ['http://localhost:3000', 'http://localhost:3001']
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = False
CSRF_COOKIE_HTTPONLY = False
CSRF_COOKIE_NAME = 'csrftoken'
CSRF_COOKIE_DOMAIN = 'localhost'

I commented all the CSRF settings and tested it. The results are the same. I still need the CORS settings; otherwise, the api requests do not work.

According to the docs, ‘django.middleware.csrf.CsrfViewMiddleware’ creates the CSRFtoken and we can get the token through the get_token method.

@ensure_csrf_cookie
def get_csrf_token(request):
    token = get_token(request)
    response = JsonResponse({'csrfToken': token})
    response.set_cookie(settings.CSRF_COOKIE_NAME, token, domain='localhost')
    return response

Here are my api endpoints in my url file

urlpatterns = [
    path("createVectorDatabase/", views.generate_database, name="createVectorDatabase"),
    path("deleteNamespace/", views.deleteNamespace, name="deleteNamespace"),
    path("getLLMInventoryDisclosureResponse/", views.getLLMInventoryDisclosureResponse, name="getLLMInventoryDisclosureResponse"),
    path('api/csrf_token/', views.get_csrf_token, name="get_csrf_token"),
    path('testCsrfProtect/',views.test_csrf_protect, name="test_csrf_protect")
]

Here is my post method that I will try to call in my frontend

@api_view(["POST"])
@csrf_protect
def generate_database(request):
    files, directory_path, error = upload_pdf(request)
    if error != None:
        return error
    loader = DirectoryLoader(directory_path, glob="*.pdf")
    documents = loader.load()
    chunks = split_text(documents)
    namespace = request.GET.get("namespace")
    save_to_pinecone(chunks, namespace)
    delete_files(files)
    return JsonResponse({"message": "Vector database has created."})

Now to my react frontend. During the initial load of my app, I use the useEffect hook to get the token from the backend.

const fetchCsrfToken = async () => {
  const response = await axios.get('http://localhost:8000/api/csrf_token/');
  const csrftoken = response.data.csrfToken;
  Cookies.set('csrftoken', csrftoken, { domain: 'localhost' });
  return csrftoken;
};

function App() {
  useEffect(() => {
    fetchCsrfToken().then(csrftoken => {
        console.log('CSRF Token fetched:', csrftoken);
    });
  }, []);  // The empty dependency array ensures this runs only once on mount

Here is the api request that calls the generateDatabase method in the backend. The summary of this method is that it takes in pdfs and sends it to the backend.

export const sumbitDocuments = (selectedFiles, setUploadResponse) => {
    const csrftoken = Cookies.get('csrftoken');
    console.log("csrftoken in submit", csrftoken)
    const formData = new FormData();
    for (let i = 0; i < selectedFiles.length; i++) {
        formData.append(`pdf_file`, selectedFiles[i]);
    }
    const upload_path = HOST_PATH + '/' + 'createVectorDatabase/'
    const namespace = {'namespace': 'Georgia-Tech-Inventory-Disclosure'}
    axios.post(upload_path, formData, {
        headers: {
            'X-CSRFToken': csrftoken
        },
        withCredentials: true,
        params: namespace
    }).then((response) => {
        var response_key = Object.keys(response.data)[0]
        if (response_key === "error") {
            setUploadResponse(response.data["error"])
        } else {
            setUploadResponse(response.data["message"])
        }
        }
    ).catch((error) => {
        console.log("axios error ", error)
    }); 
};

Now when I test my application, the token logged in the backend is the same token that is printed in the console in the frontend. Additionally, when I go to application → cookies in chrome dev tools, the same cookie is there. When I look at the request summary in the network tab, the token is listed under X-crsftoken.

Not sure if i should show the entire token so i hid a portion of it.

Even though the tokens match, i still get CSRF vertification error.

Now, when I remove csrf_protect, the api request works. I do not even need to send the csrftoken in.

I would appreciate any help as I do not know what to do. Chat gpt says the same thing over and over again and eventually said send your question to a forum.

You CSRF_TRUSTED_ORIGINS is using port 3000 and 3001 and you request is to port :8000

I thought CSRF_TRUSTED_ORIGINS should list urls where requests can come from.

Settings | Django documentation | Django.

As a result, I do not think this is an issue. Please correct me if I am wrong

Sorry! You are correct.

You get CSRF Token just only time?

I think that you have to get a new token before send POST request.