diff --git a/backend/config/settings.py b/backend/config/settings.py index 27b9e03..1d0a026 100644 --- a/backend/config/settings.py +++ b/backend/config/settings.py @@ -95,6 +95,7 @@ DATABASES = { } CORS_ALLOWED_ORIGINS = env.list("CORS_ALLOWED_ORIGINS") +CORS_ALLOW_CREDENTIALS = True # allow cookies with frontend AUTH_USER_MODEL = "users.User" diff --git a/backend/users/utils.py b/backend/users/utils.py index 4fabd00..ac734fb 100644 --- a/backend/users/utils.py +++ b/backend/users/utils.py @@ -20,3 +20,19 @@ def send_activation_email(user): If you did not create this account, please ignore this email.""" send_mail(subject, message, settings.FROM_EMAIL, [user.email], fail_silently=False) return True + + +def set_response_cookies(response, refresh_token): + _response = response + if "refresh" in _response.data: + del _response.data["refresh"] # remove refresh token from response body + _response.set_cookie( + key=settings.SIMPLE_JWT["AUTH_COOKIE"], + value=refresh_token, + max_age=settings.SIMPLE_JWT["REFRESH_TOKEN_LIFETIME"].total_seconds(), + httponly=settings.SIMPLE_JWT["AUTH_COOKIE_HTTPONLY"], + secure=settings.SIMPLE_JWT["AUTH_COOKIE_SECURE"], + samesite=settings.SIMPLE_JWT["AUTH_COOKIE_SAMESITE"], + domain=settings.SIMPLE_JWT["AUTH_COOKIE_DOMAIN"], + ) + return _response diff --git a/backend/users/views.py b/backend/users/views.py index 5b53607..bd2f99a 100644 --- a/backend/users/views.py +++ b/backend/users/views.py @@ -4,8 +4,10 @@ from django.db import transaction from django.utils.http import urlsafe_base64_decode from rest_framework import generics, permissions, status from rest_framework.response import Response +from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView -from users.utils import send_activation_email +from config import settings +from users.utils import send_activation_email, set_response_cookies from .serializers import UserSerializer @@ -50,3 +52,25 @@ class MeView(generics.RetrieveAPIView): def get_object(self): # Returns the user associated with the JWT token in the request return self.request.user + + +class TokenLoginView(TokenObtainPairView): + def post(self, request, *args, **kwargs): + response = super().post(request, *args, **kwargs) + if response.status_code == status.HTTP_200_OK: + refresh_token = response.data["refresh"] + response = set_response_cookies(response, refresh_token) + return response + + +class RefreshTokenView(TokenRefreshView): + def post(self, request, *args, **kwargs): + refresh_token = request.COOKIES.get(settings.SIMPLE_JWT["AUTH_COOKIE"]) + if not refresh_token: + return Response({"detail": "Refresh token not found"}, status=status.HTTP_401_UNAUTHORIZED) + request.data["refresh"] = refresh_token + response = super().post(request, *args, **kwargs) + if response.status_code == status.HTTP_200_OK: + new_refresh_token = response.data["refresh"] + response = set_response_cookies(response, new_refresh_token) + return response