0

First, I know there are many questions regarding CSRF tokens / Django, but I haven't found any that are useful for the scenario that I am in.

I am attempting to use Django's built in password reset endpoints with a React frontend. My goal is to use the backend functionality (generating tokens, email responses, etc) while displaying the relevant forms through React instead of using Django templates. The front end and back end are hosted on two unique servers.

In my front end code, I make a call to the password_reset endpoint when my React component mounts to fetch the CSRF token.

    componentDidMount() {
        let url = "http://(raw ip address)/accounts/password_reset/"

        fetch(url, {
            credentials: 'include',
        })
    }

The token is received in the Response headers as

Set-Cookie: csrftoken=b...e; expires=Sun, 10 Jan 2021 21:50:20 GMT; Max-Age=31449600; Path=/; SameSite=Lax

Here are where my issues begin - I am unable to inspect the token in my storage tab and the token value is not present in document.cookie. Ideally, I would like to use something like the getCookie method that is demonstrated in the 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;
}

But that assumes that the token value is properly stored in document.cookie.

My relevant Django settings are all the default values, although I have rotated through the valid options for CSRF_COOKIE_SAMESITE and CSRF_USE_SESSIONS to no avail.

As another note, if I make a POST request once the component is mounted, the token is successfully set on the Request - but I need to add the token in the body for the default Django authentication views!

Any suggestions or insight would be greatly appreciated!

Ian

ihunter2839
  • 77
  • 1
  • 2
  • 14

1 Answers1

0

According to Django docs, if your view doesn’t render an html template with csrf_token tag in it, which I guess is your case since you are not using Django’s built-in template for output, the cookie will not be set. One possible solution to this would be wrap your view call to ensure_csrf_token decorator in your urlpatterns.

  • I haven't modified Django's authentication views, so it is technically still rendering the default template. I will look more into ensure_csrf_token, but at that point I feel I am better off re-writing the authentication endpoints. – ihunter2839 Jan 13 '20 at 00:00
  • Sorry, I have not understood your question fully at first. It looks like the problem is not on the Django side here cause it sends Set-Cookie header with csrftoken in a response. The problem is that, as I understand, it's browser's responsibility to set cookies. It does so when it receives Set-Cookie header in the first place, but in your example, this header is sent in subsequent request that your React app makes to backend. Therefore, you have to set cookie manually after receiving response in your React app. [js-cookie](https://github.com/js-cookie/js-cookie) library will be helpful. – Olzhas Arystanov Jan 14 '20 at 17:22
  • Unfortunately js-cookie is also not a valid solution, as it is unable to read the cookie's value - that is `Cookies.get('csrftoken') === undefined` I assume that the cookie would need to be visible through `document.cookie` before `js-cookies` will pick it up. I ended up using Django's password token generator in a custom view - it doesn't have csrf protection as of now but it is a working solution for testing purposes. – ihunter2839 Jan 15 '20 at 19:34