3

I am receiving an error from Django that the "CSRF token is missing or incorrect" along with its standard error message. Many other questions have covered the right response when you're working with a standard browser and a Django server, but I'm trying to get UnityWebRequest to play nicely with Django.

Conceptually, I have two steps. First, I'm calling a GET request on my login page, parsing out the csrfmiddlewaretoken from my form, and the csrftoken from the set-cookie header.

Then, I make a second UnityWebRequest that includes the "referer" as a header and the csrftoken as a header in the cookies. I would add in to the form the username and password and csrfmiddlewaretoken, but the error is present either way.

Are there other headers or cookies to set? I assume my trouble is that I'm trying to emulate the behavior of a web browser in Unity, and that's complicated.

    UnityWebRequest loginPage = UnityWebRequest.Get("https://dividedsky.herokuapp.com/accounts/login/");
    yield return loginPage.SendWebRequest ();
    if(loginPage.isNetworkError || loginPage.isHttpError) {
        Debug.Log(loginPage.error);
        yield break;
    }

    // get the csrf cookie
    string SetCookie = loginPage.GetResponseHeader ("set-cookie");
    Debug.Log (SetCookie);
    Regex rxCookie = new Regex("csrftoken=(?<csrf_token>.{64});");
    MatchCollection cookieMatches = rxCookie.Matches (SetCookie);
    string csrfCookie = cookieMatches[0].Groups ["csrf_token"].Value;

    // get the middleware value
    string loginPageHtml = loginPage.downloadHandler.text;
    Regex rxMiddleware = new Regex("name='csrfmiddlewaretoken' value='(?<csrf_token>.{64})'");
    MatchCollection middlewareMatches = rxMiddleware.Matches(loginPageHtml);
    string csrfMiddlewareToken = middlewareMatches[0].Groups ["csrf_token"].Value;

    /*
     * Make a login request.
     */

    List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
    //formData.Add( new MultipartFormDataSection("username=fake") );
    //formData.Add (new MultipartFormDataSection ("password=notpass"));
    //formData.Add(new MultipartFormDataSection("csrfmiddlewaretoken=" + csrfMiddlewareToken));

    UnityWebRequest doLogin = UnityWebRequest.Post("https://dividedsky.herokuapp.com/accounts/login/", formData);

    doLogin.SetRequestHeader ("referer", "https://dividedsky.herokuapp.com/accounts/login/");
    Debug.Log (doLogin.GetRequestHeader ("cookie"));
    doLogin.SetRequestHeader ("cookie", "csrftoken=" + csrfCookie);
    Debug.Log (doLogin.GetRequestHeader ("cookie"));

    yield return doLogin.SendWebRequest ();

    Debug.Log (doLogin.downloadHandler.text);
Mark Miller
  • 706
  • 4
  • 14

2 Answers2

1

(2020 Edit: See also Jonathan's response)

It turns out the final important part was to set a X-CSRFToken header.

doLogin.SetRequestHeader ("referer", "https://dividedsky.herokuapp.com/accounts/login/");
doLogin.SetRequestHeader ("cookie", "csrftoken=" + csrfCookie);
doLogin.SetRequestHeader ("X-CSRFToken", csrfCookie);
Mark Miller
  • 706
  • 4
  • 14
1

Just an update to this post as I was trying to use this myself to post to Django with Unity. The code is good save for one change. The below line of code will cause an error and should not be used with Unity 2018.3 or later.

doLogin.SetRequestHeader ("cookie", "csrftoken=" + csrfCookie);

This is because Unity manages cookies itself so you should NOT set a cookie header. The rest of the code worked for me once I took out that line.

Jonathan
  • 11
  • 1