1

My HTTP only cookie is being received by the frontend, but not passed in subsequent requests to the backend, therefore ruining my authentication process.

I want to add authentication to a page in my React app. Part of this involves making an authenticated request to my Django API. The endpoint is set up with this authentication class:

from rest_framework.authentication import TokenAuthentication from rest_framework.exceptions import AuthenticationFailed class CookieTokenAuthentication(TokenAuthentication): def authenticate(self, request): token = request.COOKIES.get('authToken') print(f'Cookies: {request.COOKIES}') # printing cookies for debugging print(f'Token: {token}') if not token: raise AuthenticationFailed('No token provided') token_model = self.get_model() try: token_obj = token_model.objects.get(key=token) except token_model.DoesNotExist: raise AuthenticationFailed('Invalid token') if token_obj.expiry < timezone.now(): raise AuthenticationFailed('Token expired') return (token_obj.user, token_obj) 

Since this requires an authToken, I have generated an authToken based on the default user model. Here's the class for doing that:

 authentication_classes = [] def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] expiry = timezone.now() + timedelta(days=7) token, created = Token.objects.get_or_create(user=user) if not created: token.expiry = expiry token.save() response = Response({ 'user_id': user.pk, 'expiry': expiry.isoformat() }) response.set_cookie( key='authToken', value=token.key, httponly=True, secure=True, samesite='None', expires=expiry, domain='localhost', path='/' ) return response 

I can verify that the authToken is being sent to the user because I can see the "set_cookie" header in the response to the user logging in. I had to make this a HTTP-only cookie because I didn't want to be vulnerable to XSS attacks. Apparently when samesite='False' you need to also set secure=True, so I had to go down the HTTPS route...

I've generated a self-signed SSL certificate using OpenSSL for development on localhost. Then, I configured my React frontend and Django backend to launch with HTTPS. I did this for Django by installing django-extensions/Werkzeug and running a command which pointed at the certificate/private key, and for React by specifying HTTPS and the cert/key in 'vite.config.js'. Both the front and backend servers are running on HTTPS.

I then had some problems in Chrome with the webpage being insecure, so I enabled the Chrome Flag 'allow-insecure-localhost' and I added the localhost certificate to the 'Trusted Root Certificate Authorities'. After restarting the cache and reloading my web app in Chrome, I logged into my site. It sent the cookie in the HTTPS response header when the user logged in, but subsequent requests didn't contain the cookie (I checked this with the authentication class that I've displayed in this post, which prints the request's cookies).

My relevant Django settings are as follows:

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'rest_framework', 'django_filters', 'EstrayaApp.apps.EstrayaappConfig', 'corsheaders', 'rest_framework.authtoken', 'django_extensions', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'EstrayaApp.middleware.TokenExpiryMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] CSRF_COOKIE_SECURE = True CSRF_COOKIE_HTTPONLY = True SESSION_COOKIE_SECURE = True SESSION_COOKIE_HTTPONLY = True SESSION_COOKIE_SAMESITE = 'None' CSRF_COOKIE_SAMESITE = 'None' CORS_ALLOW_CREDENTIALS = True CORS_ALLOWED_ORIGINS = [ 'https://localhost:5173', 'https://localhost:8000', ] REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'EstrayaApp.authentication.CookieTokenAuthentication', 'rest_framework.authentication.TokenAuthentication', ] } 

Finally, here's the React function which is making the authenticated request:

 const fetchTargetSkill = async (skill) => { const response = await fetch(`https://127.0.0.1:8000/usertask-byskill/${skill.id}/`, { method: 'GET', credentials: 'include', }); 

I feel like I've tried everything. Nobody else's posts are directly relevant and I'm lost now. Any help would be appreciated, thanks.

3
  • 1
    Do you find any similarity with this stackoverflow.com/questions/71201627/… Commented Feb 7, 2024 at 2:08
  • Yes you may be right, I haven't set credentials = True for receiving the cookie, only for sending it. I will try later and confirm. Thanks Soumen Commented Feb 7, 2024 at 10:38
  • 1
    Hi Soumen, you're right, that was the issue. However, I also had to remove "domain" attribute from the cookie as the different localhost ports were affecting it. This can be closed. Thank you :) Commented Feb 7, 2024 at 20:30

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.