Search code examples
djangoreactjsdjango-cors-headers

Django React CSRF Issues


Building my first app using Django as back end and React as front end.

Locally, I have both running on port 8000 and 3000 respectively.

I have a short snippet of code I found online to help me test whether or not my CSRF and CORS policies are set correctly:

const API_HOST = 'http://localhost:8000';

let _csrfToken = null;

async function getCsrfToken() {
  if (_csrfToken === null) {
    const response = await fetch(`${API_HOST}/csrf/`, {
      credentials: 'include',
    });
    const data = await response.json();
    _csrfToken = data.csrfToken;
  }
  return _csrfToken;
}

async function testRequest(method) {
  const response = await fetch(`${API_HOST}/ping/`, {
    method: method,
    headers: (
      method === 'POST'
        ? {'X-CSRFToken': await getCsrfToken()}
        : {}
    ),
    credentials: 'include',
  });
  const data = await response.json();
  return data.result;
}


class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      testGet: 'KO',
      testPost: 'KO',
    };
  }

  async componentDidMount() {
    this.setState({
      testGet: await testRequest('GET'),
      testPost: await testRequest('POST'),
    });
  }

  render() {
    return (
      <div>
        <p>Test GET request: {this.state.testGet}</p>
        <p>Test POST request: {this.state.testPost}</p>
      </div>
    );
  }
}

export default App;

EDIT to clarify: Remote GET request passes, only POST fails

When I run this code locally, I get the correct response which is, the "KO" gets changed to "OK" when the responses come back valid.

This only works from my machine. If I try to access it from any other machine in my network, I get the following error:

403 Forbidden

Django's debug reason is that "CSRF cookie not set".

However, in the console, I can see the headers are indeed sending the X-CSRFToken.

I have a "live" version of my backend that I've also tried to tap into with same results as locally.

I only get a successful test if I try it from my own computer, where both dev servers sit.

Django settings:

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = ['localhost:3000', 'My_Public_Ip:3000']

I suspect my issue is somewhere in that whitelist but I'm at a loss at this point to find what it is.

If someone could help me understand what's happening, if they don't have an answer, that might trigger an "aha" moment.


Solution

  • Besides @tgdn's recommendation of getting the token from the cookie i would also recommend checking your SameSite policy settings for the CSRF- and Session- Cookies, as setting it to Strict or Lax will also probhibit the cookies being sent in cross-origin requests (which could result in losing your session/being logged out etc...).