# CSRF validation failure due to https

**URL:** <https://forum.djangoproject.com/t/csrf-validation-failure-due-to-https/3023>\
**Category:** Using Django\
**Created:** [June 18, 2020, 11:16am UTC](https://forum.djangoproject.com/t/csrf-validation-failure-due-to-https/3023 "2020-06-18T11:16:56Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![kpagcha](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/kpagcha/32/1217_2.png) [@kpagcha](https://forum.djangoproject.com/u/kpagcha)\
**Post date:** [June 18, 2020, 11:16am UTC](https://forum.djangoproject.com/t/csrf-validation-failure-due-to-https/3023/1 "2020-06-18T11:16:56Z")

</div>

I am testing on our staging server and am getting CSRF failures when trying to log in our proxy server or any CNAME pointing to it. The response is 403 Forbidden. This is the message I get when setting `DEBUG=True`:

> Referer checking failed - xhttp://www.app.com/accounts/login/?next=/ does not match xhttps://www.app.com/.

(“xhttp” is because the forum won’t let me post more than “2 links”… even though they’re not real links)

This is the nginx configuration:

```
upstream app_server {
    server unix:/home/app/run/gunicorn.sock fail_timeout=0;
}

# proxy server to the django app server
server {
    server_name proxy.staging.app.com;
    listen 80 default_server;

    location / {
        include proxy_params;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_pass https://staging.app.com:8080;
    }
}

# django app server
server {
    server_name staging.app.com;
    listen 80;
    listen 8080 ssl;
    listen 443 ssl; 
    # ssl certificates...

    location / {
        include proxy_params;
        proxy_redirect off;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_pass http://unix:/home/app/run/gunicorn.sock;
    }
}

# https redirect 
server {
    server_name staging.app.com;
    listen 80;
    return 301 https://$host$request_uri;
}

```

The http request is made to the proxy at [proxy.staging.app.com](http://proxy.staging.app.com) which proxy passes with a https request to the block where the Django app runs (well, where it proxies to the socket running it).

As you can see, proxy headers are included so that the Django app knows the original host, scheme, port, etc. Relevant settings are also set:

```
USE_X_FORWARDED_HOST = True
USE_X_FORWARDED_PORT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

```

The reason CSRF validation fails seems to be that the addresses don’t match because of the scheme. I really don’t understand how this is happening: everything is configured correctly so that the original host and scheme is passed to Django, therefore why is it generating a CSRF token for the wrong address? Shouldn’t it be generating it for the original http address rather than the https one?

---

<div class="post-metadata">

**Author:** ![Alir3z4](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/alir3z4/32/2976_2.png) [@Alir3z4](https://forum.djangoproject.com/u/Alir3z4)\
**Post date:** [July 14, 2020, 9:58pm UTC](https://forum.djangoproject.com/t/csrf-validation-failure-due-to-https/3023/3 "2020-07-14T21:58:45Z")

</div>

Another solution that works me which I just tried on one of the project served by Nginx is adding the following to nginx server conf:

```auto
map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
    listen 80;
    listen [::]:80;

    server_name my.backend.com *.my.backend.com

    location / {
      return 301 https://$host$request_uri;
    }
}

server {
  listen 443 ssl http2;
  server_name my.backend.com *.my.backend.com;
  ssl_certificate /etc/letsencrypt/live/my.backend.com/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/my.backend.com/privkey.pem; # managed by Certbot

  location /.well-known/acme-challenge/ {
    root /var/www/certbot;
  }

  include ssl.conf;

  location / {
    proxy_http_version 1.1;
    proxy_pass http://my_backend:8000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Upgrade $http_upgrade;
    proxy_cache_bypass $http_upgrade;
  }
}

```

In the above, the two headers that are very important are

```auto
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Host $host;

```

In the `settings.py` I have:

```python
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
USE_X_FORWARDED_HOST = True
USE_X_FORWARDED_PORT = True

```

In this configuration, I don’t need to touch [CSRF\_TRUSTED\_ORIGINS](https://docs.djangoproject.com/en/3.0/ref/settings/#std:setting-CSRF_TRUSTED_ORIGINS) at all.
