title: Django CSRF Verification Failed when using WSGIDaemonProcess with multiple processes
body: <p>My Django version is 2.2 and I've configured httpd.conf (Apache/2.4.39 (Unix) mod_auth_gssapi/1.6.1 mod_wsgi/4.6.5 Python/3.7) to start a process pool like so:</p>
  
  <pre><code>WSGIDaemonProcess my_app processes=6 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${MY_ENV_VAR}
  </code></pre>
  
  <p>With this setup, I would get <code>Forbidden 403 errors</code> with <code>CSRF verification failed</code> message when I do a POST request.</p>
  
  <p>If I keep refreshing the page, when I get lucky, my POST request would succeed. Now I'm guessing this is because the request might have landed onto the wsgi process with the Django instance that has the "right cache".</p>
  
  <p>To test the above theory, if I change the httpd.conf to have only 1 pool process like below, I do not get the 403 error.</p>
  
  <pre><code>WSGIDaemonProcess my_app processes=1 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${MY_ENV_VAR}
  </code></pre>
  
  <p>I have followed the CSRF specific instructions on <a href="https://docs.djangoproject.com/en/2.2/ref/csrf/" rel="nofollow noreferrer">Django documentation</a> and tried both scenarios when <code>CSRF_USE_SESSIONS</code> is set to <code>True</code> or <code>False</code></p>
  
  <p>What is the recommended approach to configuring Django if I intend to spin up a pool for wsgi processes each of which would run my Django app?</p>
  
  <p>I did some testing and confirmed that my views.py does not get called when the 403 error happens. So Django is rejecting the POST request before it even attempts to call views.py. Below is a snippet of the views.py:</p>
  
  <pre><code>def my_func(request):
      if request.is_ajax() and request.method == 'POST':
          # some logic
  
          try:
              response = ... # some logic to build response
              return HttpResponse(json.dumps(response), content_type="application/json")
          except Exception as e:
              return HttpResponseBadRequest('\n'.join(errors))
  
      return render(request, 'my_app/my_template.html', locals())
  </code></pre>
  
  <p>The template in use has a simple form:</p>
  
  <pre><code>&lt;form class="form-horizontal" role="form"&gt;{% csrf_token %}
  </code></pre>
  
  <p>To submit the form, there is an AJAX call:</p>
  
  <pre><code>$.ajax({
      type: "post",
      url: ".",
      data: data,
      cache: false,
      processData: false,
      contentType: false,
      success: function(response) {
          // some code
      },
      error: function(xhr, status, e) {
          // some code
      }
  });
  </code></pre>
  
  <p>This is a snippet of my httpd.conf</p>
  
  <pre><code>LimitRequestFieldSize 50000
  LimitRequestLine      50000
  TimeOut 600
  
  LoadModule access_compat_module            modules/mod_access_compat.so
  LoadModule alias_module                    modules/mod_alias.so
  LoadModule auth_gssapi_module              modules/mod_auth_gssapi.so
  LoadModule authn_core_module               modules/mod_authn_core.so
  LoadModule authz_core_module               modules/mod_authz_core.so
  LoadModule authz_host_module               modules/mod_authz_host.so
  LoadModule authz_user_module               modules/mod_authz_user.so
  LoadModule filter_module                   modules/mod_filter.so
  LoadModule info_module                     modules/mod_info.so
  LoadModule log_config_module               modules/mod_log_config.so
  LoadModule mime_module                     modules/mod_mime.so
  LoadModule mpm_prefork_module              modules/mod_mpm_prefork.so
  LoadModule negotiation_module              modules/mod_negotiation.so
  LoadModule status_module                   modules/mod_status.so
  LoadModule unixd_module                    modules/mod_unixd.so
  LoadModule wsgi_module                     modules/mod_wsgi.so
  LoadModule setenvif_module                 modules/mod_setenvif.so
  LoadModule env_module                      modules/mod_env.so
  LoadModule include_module                  modules/mod_include.so
  
  WSGISocketPrefix ${MY_SOCKET_PREFIX}
  WSGILazyInitialization On
  WSGIRestrictEmbedded On
  WSGIScriptReloading On
  
  
  WSGIDaemonProcess my_app processes=6 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${HTTPD_my_app_PYTHONPATH}
  
  #If I use the below that has processes=1 instead I do not get CSRF verification failure
  #WSGIDaemonProcess my_app processes=1 threads=12 display-name=%{GROUP} home=/tmp maximum-requests=1000 inactivity-timeout=1800 request-timeout=500 python-path=${HTTPD_my_app_PYTHONPATH}
  
  Listen ${HTTPD_my_app_PORT}
  &lt;VirtualHost *:${HTTPD_my_app_PORT}&gt;
  
      Redirect / http://${MY_HOST}:${HTTPD_my_app_PORT_REDIRECT}/
  &lt;/VirtualHost&gt;
  
  Listen ${HTTPD_my_app_PORT_REDIRECT}
  &lt;VirtualHost *:${HTTPD_my_app_PORT_REDIRECT}&gt;
      WSGIScriptAlias / ${HTTPD_my_app_BASE_DIR}/my_app_dir/wsgi.py
      WSGIProcessGroup my_app
      WSGIApplicationGroup %{GLOBAL}
  
      &lt;Directory "${HTTPD_my_app_BASE_DIR}/my_app_dir/"&gt;
        &lt;Files wsgi.py&gt;
          AuthType GSSAPI
          AuthName "MY_ENTITY/GSSAPI"
          GssapiCredStore keytab:${MY_KEYTAB}
          GssapiAllowedMech krb5
          GssapiPublishErrors On
  
          SetHandler wsgi-script
          Require valid-user
        &lt;/Files&gt;
      &lt;/Directory&gt;
  
      &lt;Directory ${HTTPD_my_app_BASE_DIR}/my_app_dir/media&gt;
          Require all granted
      &lt;/Directory&gt;
  
      &lt;Directory ${HTTPD_my_app_BASE_DIR}/static_files&gt;
         Require all granted
      &lt;/Directory&gt;
  &lt;/VirtualHost&gt;
  </code></pre>