Django admin csrf token not set

Question:

I have a Django project working locally with login to the admin portal working. Once the project has been deployed to our development environment the pages that do not require CSRF authentication are viewable, but the admin portal returns a CSRF token error when attempting to login.
Error received: CSRF cookie not set
The project is meant to be deployed to a subdomain (ie https://project.myapp.com) with the development/staging version deployed to a different subdomain (https://project.dev.myapp.com).

Subset of the settings.py:

ALLOWED_HOSTS = ['*']
CSRF_COOKIE_SECURE = False


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.gis',
    'django.contrib.messages',
    'django.contrib.sessions',
    'django.contrib.staticfiles',
    'django_object_actions',
]

MIDDLEWARE = (
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

Originally I assumed that the issue was due to the project being deployed on a subdomain and followed the documentation for csrf and added the CSRF_TRUSTED_ORIGINS = ['https://*.myapp.com'] to the settings but the issue persists.

I also tried setting the CSRF_COOKIE_DOMAIN setting to either .myapp.com or to .dev.myapp.com but continue to see the same issue.

I had also seen people mention the django.template.context_processors.csrf option to add to the TEMPLATES context_processors and tried that, but this also had no effect.

When looking at the request to the /admin/login view, a csrfmiddlewaretoken is included, but nothing is being set in the browser.

Is there a different setting I’m missing?

P.S.
The deployment is run with uwsgi behind nginx but since the pages are all still served properly I’m (maybe incorrectly) assuming the issue doesn’t lie there.

Edit:
Adding the NGINX config files being used – im not very well versed in NGINX but I don’t believe anything would be stripping the cookie header.

nginx.conf

user              nginx;
worker_processes  auto;

error_log  /dev/stderr warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format main '$realip_remote_addr [$time_local] "$request" '
                    '$status $body_bytes_sent $request_time '
                    '"$http_referer" "$http_user_agent" '
                    '"$http_x_amzn_trace_id" "$http_x_amz_cf_id"';

    access_log /dev/stdout main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    #maximum file size
    client_max_body_size 0;

    include /etc/nginx/conf.d/*.conf;
}

server.conf

upstream myapp {
  server 127.0.0.1:8000;
}

server {
  listen 7999 default_server;
  server_name $GENERAL_SUBDOMAIN.$GENERAL_DOMAIN;

  include /etc/nginx/conf.d/myapp.params;

  # Enable RealIP
  real_ip_header      X-Forwarded-For;
  real_ip_recursive   on;
  set_real_ip_from    0.0.0.0/0;
  uninitialized_variable_warn off;


  resolver 8.8.8.8;

  location /static/admin {
    uwsgi_pass myapp;
    include uwsgi_params;

    uwsgi_read_timeout 600;
    uwsgi_send_timeout 600;
    uwsgi_ignore_client_abort on;

    expires $static_expires;
  }

  location /static {
    root /app;
    expires $static_expires;
  }

  location / {
    uwsgi_pass myapp;
    include uwsgi_params;

    uwsgi_read_timeout 600;
    uwsgi_send_timeout 600;
    uwsgi_ignore_client_abort on;

    expires $static_expires;
  }
}
# vim: ft=nginx ts=2 sw=2

myapp.params

error_page 497 https://$best_http_host:$server_port$request_uri;

# vim: ft=nginx ts=2 sw=2
Asked By: Buns

||

Answers:

Maybe you could make SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE flags are matching. You’ve set CSRF_COOKIE_SECURE = False. If SESSION_COOKIE_SECURE is True, then it might be causing the issue. You should either set both flags to be False during development or set them both True for a production HTTPS environment.

SESSION_COOKIE_SECURE = False
CSRF_COOKIE_SECURE = False

For CSRF Cookie Domain, when you move to a new subdomain, the period . at the start is crucial. This ensures all sub-domains are included.

CSRF_COOKIE_DOMAIN = '.myapp.com'

And, it might be beneficial to ensure that your NGINX configuration isn’t stripping out the "Cookie" header for some reason. The CSRF Token mechanism in Django works by comparing a value stored in your session cookie to a value sent in a hidden form field or HTTP header. If your NGINX configuration isn’t properly forwarding along the Cookie header, this could cause the issue.

Answered By: Malvin Lok

The issue actually lied with the deployment itself. The server is sitting behind an AWS cloudfront distribution which was not forwarding the cookie header to the server. @malvin’s comment about logging the cookie in the NGINX logs was what lead to the discovery.

Answered By: Buns
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.