feat: implement secure HTTP-only cookie-based refresh token authentication

This commit is contained in:
Your Name
2026-04-10 17:54:49 +05:30
parent 083936d036
commit 0d37242f0d
3 changed files with 42 additions and 1 deletions
+1
View File
@@ -95,6 +95,7 @@ DATABASES = {
} }
CORS_ALLOWED_ORIGINS = env.list("CORS_ALLOWED_ORIGINS") CORS_ALLOWED_ORIGINS = env.list("CORS_ALLOWED_ORIGINS")
CORS_ALLOW_CREDENTIALS = True # allow cookies with frontend
AUTH_USER_MODEL = "users.User" AUTH_USER_MODEL = "users.User"
+16
View File
@@ -20,3 +20,19 @@ def send_activation_email(user):
If you did not create this account, please ignore this email.""" If you did not create this account, please ignore this email."""
send_mail(subject, message, settings.FROM_EMAIL, [user.email], fail_silently=False) send_mail(subject, message, settings.FROM_EMAIL, [user.email], fail_silently=False)
return True 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
+25 -1
View File
@@ -4,8 +4,10 @@ from django.db import transaction
from django.utils.http import urlsafe_base64_decode from django.utils.http import urlsafe_base64_decode
from rest_framework import generics, permissions, status from rest_framework import generics, permissions, status
from rest_framework.response import Response 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 from .serializers import UserSerializer
@@ -50,3 +52,25 @@ class MeView(generics.RetrieveAPIView):
def get_object(self): def get_object(self):
# Returns the user associated with the JWT token in the request # Returns the user associated with the JWT token in the request
return self.request.user 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