djangodockerdocker-composedjango-sessions

Session ID getting changed on redirect django & docker


I have a Django and react project. I'm using Nginx and Gunicorn to run the application. To run all these I'm using docker.

So in a Django view, I'm setting a session variable and then redirecting to another view. So in that redirected view when I'm trying to access the session variable it's not getting fetched.

enter image description here

I'm using the default session to store the session in the django_session table. I checked there as well, it's getting stored session values in the django_session table. But I'm really not understanding why it's not able to fetch the session value.

The wired part is here that in firefox it's working but not in Chrome.

The same project is working in my local (without docker) by running the Django's runserver command.

Below is how my docker-compose.test.yml file looks like

version: "3.8"

services:
    db:
        image: postgres:12.3
        ports:
          - "5432:5432"
        env_file:
          - ./env/.env.dev.db
        volumes:
          - postgres_data:/var/lib/postgresql/data/
        networks:
          - backend
    app:
        build:
          context: .
          dockerfile: ./docker/test-env/app-docker/Dockerfile
          args:
              - REACT_APP_API_URL=http://127.0.0.1
        volumes:
          - app_static_files:/app/static

        command: >
          /bin/sh -c
          "python manage.py migrate
          && python manage.py collectstatic --no-input
          && gunicorn -w 4 --bind 0.0.0.0:8000 app.wsgi
          "
        env_file:
          - ./env/.env.dev.db
          - ./env/.env.dev
        ports:
          - "8000:8000"
        depends_on:
          - db
        networks:
          - backend
    nginx:
        build:
          context: .
          dockerfile: ./docker/test-env/nginx/Dockerfile
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - app_static_files:/project_static_files
        depends_on:
          - app
        networks:
          - backend

volumes:
    postgres_data:
    app_static_files:
networks:
    backend:

And this is how my app docker file looks like.

# BUILD FRONT END
FROM node:12.17.0-alpine3.11 as frontend

ARG REACT_APP_API_URL
ENV REACT_APP_API_URL $REACT_APP_API_URL

WORKDIR /app
COPY ./app/front_end/app-frontend/ /app

RUN npm install

RUN npm run build

# APPLICATION
FROM python:3.8.3-slim

ENV PATH="/app:${PATH}"

WORKDIR /app

RUN apt-get update && apt-get install -y gcc libxml2-dev libxmlsec1-dev pkg-config  \
   && apt-get -y install libsasl2-dev libldap2-dev libssl-dev libxmlsec1-openssl python3-dev

COPY ./app/ /app

COPY --from=frontend /app/build /app/front_end/noa-frontend/

RUN pip install -r production_requirements.txt --no-cache-dir

Below is the Nginx configuration

server {
    listen 80;
    server_name $server_addr;
    access_log  /var/log/nginx/example.log;

    location /static/ {
        autoindex off;
        alias /project_static_files/;
    }

    location / {
        proxy_pass http://app:8000;
        proxy_pass_request_headers on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Port $server_port; 
    }
}

Please someone please help me, I couldn't find anything on the internet regarding this.

This project I'm running on

  1. Windows 10 pro
  2. Docker version 19.03.8, build afacb8b
  3. docker-compose version 1.25.5, build 8a1c60f6

Update:

I tried the Django's runserver as well to test if it's at least working with Django's runserver in a docker container. But no, I'm facing the same issue in Chrome, but in Firefox it's working properly :(

In the error I could see, to Chrome only csrftoken is being passed. Whereas to Firefox both csrftoken and sessionid is being passed.

Cookies passed to Chrome enter image description here

Cookies passed to Firefox enter image description here


Solution

  • I figured out what was happening.

    I have a environment variables file. In that, I have set the below lines

    SESSION_COOKIE_SECURE_VAL=0

    CSRF_COOKIE_SECURE_VAL=0

    DEV_ENV=1

    and in the settings.py I have

    SESSION_COOKIE_SECURE = bool(int(os.environ.get("SESSION_COOKIE_SECURE_VAL")))
    CSRF_COOKIE_SECURE = bool(int(os.environ.get("CSRF_COOKIE_SECURE_VAL")))
    

    So 0 is for False and 1 is for True. Even though I have set 0 (False) for SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE, it was taking 1 i.e True (I really don't know why it's taking 1 as default, even though I'm setting the environment values for those)

    In the Django docs, it's mentioned as below enter image description here

    So what I did was change the logic in the settings.py file like below

    if not bool(int(os.environ.get("DEV_ENV", default=1))):
        SESSION_COOKIE_SECURE = True
        CSRF_COOKIE_SECURE = True
    

    So my development environment is not HTTPS, so check if it's not dev environment then don't set the SESSION_COOKIE_SECURE and CSRF_COOKIE_SECURE (In this case both will False by default)

    I'm not sure why Firefox was able to set the cookie under this setting.

    If any better answeres are there please answer.

    And I hope this will help, if anyone is facing the same issue.