loading...

Django Sessions not working as expected when using cors

rincorpes profile image Santiago Rincón ・2 min read

I have this app with Django and rest_framework and another one with Express. The Django one has an endpoint to log users in, auth/login. The Express app has a form that posts the user data to a route which, using axios, makes an API call to the Django app to log the user in.

When I test the endpoint from the DRF view it works perfectly but the problem comes when I try to login from the Express app.

Here is the endpoint view

# view.py

from django.contrib.auth import authenticate, login
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from rest_framework import status

@api_view(['POST'])
@permission_classes([AllowAny,])
def api_login(request):

  username = request.data["username"]
  password = request.data["password"]

  user = authenticate(request, username=username, password=password)

  if user is not None:
     login(request, user)
     return Response(status=status.HTTP_200_OK)

  return Response(status=status.HTTP_400_BAD_REQUEST)

On the DRF view, I add a valid username and password, I post it and everything works fine. I can enter the Django admin panel, and there is a cookie for the session id as it is supposed to be.

Here is the Express app route code

...
const axios = require('axios')

axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.withCredentials = true

...

router.post('/login', (req, res) => {
  axios.post('http://127.0.0.1:8000/auth/login/', req.body)
    .then(rv => {
      console.log('login', rv)
      res.send('Login')
    })
    .catch(err => {
      console.log('error', err)
      res.send('Error')
    })
})
...

Here is where things turn weird. This almost works. The endpoint receives the data, the user is authenticated, it returns status code 200, and even the session is stored into the database but there is no cookie named sessionid which is what I am expecting.

I'm using cors this way

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'corsheaders',
    'auth',
]

MIDDLEWARE = [
     'corsheaders.middleware.CorsMiddleware',
     ...
]

CORS_ORIGIN_ALLOW_ALL = False

CORS_ORIGIN_WHITELIST = (
    'http://127.0.0.1:4200',
)

CSRF_TRUSTED_ORIGINS = [
    'http://127.0.0.1:4200',
]

CORS_ALLOW_CREDENTIALS = True

BTW, I have another endpoint just like this but to register new users and it works perfectly from the Express app, so I don't know. I guess something is wrong on my Django app settings file but I'm not sure. I hope someone here can help me with this.

Posted on by:

rincorpes profile

Santiago Rincón

@rincorpes

Code, eat, play Minecraft, sleep, repeat.

Discussion

markdown guide
 

I'm not familiar with these tools but I noticed this on the readme of django-cors-headers:

Note: in Django 2.1 the SESSION_COOKIE_SAMESITE setting was added, set to 'Lax' by default, which will prevent Django's session cookie being sent cross-domain. Change it to None to bypass this security restriction.

Could it be that the cookie the server is setting isn't correctly configured for cross domain requests?

See also docs.djangoproject.com/en/2.2/ref/...

Let me know if we are on the right path :)

 

I already tried that but it didn't work. Someone at StackOverflow told me I needed it to create a token in the Express app and send it with the user data to the Django app. I will try that. I'll let you know.