Forums

403 Forbidden for POST with data, fine without (and works fine on local)

My React App frontend Django backend on pythonanywhere.com is failing to save (POST to Django REST API with data) with a Forbidden 403 message.

On my local machine, it works perfectly fine -- it can both make the API call to "load" and the API call to "save" the state of the React App's data, which are two separate API calls.

When I put it on pythonanywhere, however, it can only "load" correctly -- that API goes off without a hitch. But, whenever it tries to save, it won't even attempt to run the APIView that it's supposed to, it immediately rejects it as 403 forbidden and will not run the "save" code.

(I tried putting in some "print" statements into the save code to see if it accessed it at all, and it didn't, it rejects it without running any of it, unfortunately.)

What could this be caused by? This is super frustrating, have been trying for awhile to figure this out but it's not getting sorted.

A 403 suggests that the authentication that you're providing from react may be different between the 2 deploys. Perhaps the authentication config is somehow derived from other config or taken from a database that you have not provided to the code on PythonAnywhere, or something like that.

Thanks Glenn!

Now that it's a fresh day and my cranky is less --

That is a good starting off point to dive into this further, it excludes issues with the code that I kept tampering with to no avail.

That said, the settings.py (for Django), and even the database (sqlite) are the same exact files, on both my local machine and pythonanywhere's server, they are literally part of the git (terrible practice I know but it's a very simple app I made quickly, www.predictit2020.com)

Could you elaborate a bit on the authentication configuration? Is there something else I'm missing?

The authentication configuration that Glenn was talking about would be something specific to your code; however, if I'm understanding correctly what you're seeing in the results of your debugging with prints,, your code is not being run at all for those POST requests -- is that right? If so, perhaps one of Django's security mechanisms is rejecting the POSTs.

If it is, perhaps a good next step for debugging would be for you to switch Django's DEBUG mode on temporarily, and then take a look at the responses that are being sent back to your React code using the browser's developer tools. In debug mode, Django will give details of why it's rejecting requests. My first guess would be that it's something to do with CSRF, but it's probably best to get the details from Django itself rather than start digging around in that area without hard evidence.

Edit: I fixed this, it was a problem with the "getCookie" function which was having difficulty with pythonanyhwhere's cookie setup vs. localhost.

All good now, changed the code from this:

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]
        // Does this cookie string begin with the name we want?
        if (cookie.substring(1, name.length + 1) === name) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 2));
            break;
        }
    }
}

to this:

  if (document.cookie && document.cookie !== '') {
    let cookies = document.cookie.split(';')
    console.log(cookies)

    for(let i = 0;i < cookies.length; i++) {
        let cookie = cookies[i]
        let [cookieName, val] = cookie.split("=")
        cookieName = cookieName.trim()
        if(name===cookieName) return val
    }
}

Ahh wait a tick, I take it back, it is some problem with the CRSF Token. I made the React app spit out the output of the CRSF token after getting it out of cookies, and on the local machine it is a string of chars ( a legit token ) but on pythonanyhwere it's "null".

Here's the code for the getCookie function that seems to be failing:

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]
        // Does this cookie string begin with the name we want?
        if (cookie.substring(1, name.length + 1) === name) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 2));
            break;
        }
    }
}
return cookieValue;
}

What are you able to see if you log what happens with your requests on the django side (locally and on PA)?

Unfortunately the logs just seemed to indicate that it was 403 forbidden, it wasn't saying anything about CSRF verification but of course it ended up being the CSRF verification with an issue interpreting the cookie string on pythonanywhere that was different than my local machine's cookie string.

Thank you all for your help though

Have a nice week!

Glad to hear that you made it work.