I am using the Django REST Framework with dj-rest-auth
and django-allauth
for authentication and authorisation with JWTs. From what I have heard, using HTTP-only cookies to store the tokens is a secure approach where the access token is passed in the response body but the refresh token is passed to the browser as a cookie.
The default (straight from dj_rest_auth.registration.views) login endpoint works this way, returning the access token in the response body and returning the access and refresh tokens as HTTP-only cookies as well as a csrftoken and sessionid. However, the default signup endpoint doesn't exhibit the same behaviour, it returns both access and refresh tokens in the response body and returns neither as a cookie, but does return these cookies: messages, csrftoken, sessionid. Does anyone know why this might be happening and how I could get registration to behave the same way as login? Here are the relevant parts of my settings.py:
REST_AUTH = {
"USE_JWT": True,
"JWT_AUTH_COOKIE": "access-tkk",
"JWT_AUTH_REFRESH_COOKIE": "refresh-tkk",
# "JWT_AUTH_SECURE": True, # Use secure cookies in production for HTTPS only
"JWT_AUTH_HTTPONLY": True, # Secure HTTP-only cookies
"REGISTER_SERIALIZER": "authentication.serializers.CustomRegisterSerializer",
"USER_DETAILS_SERIALIZER": "authentication.serializers.CustomUserDetailsSerializer",
}
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=15), # Short-lived access token
"REFRESH_TOKEN_LIFETIME": timedelta(days=14), # Longer-lived refresh token
"ROTATE_REFRESH_TOKENS": True, # Issue new refresh token on refresh
"BLACKLIST_AFTER_ROTATION": True, # Blacklist old refresh tokens
"UPDATE_LAST_LOGIN": True,
"ALGORITHM": "HS256",
"AUTH_HEADER_TYPES": ("Bearer",),
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
}
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": (
"dj_rest_auth.jwt_auth.JWTCookieAuthentication",
"rest_framework.authentication.TokenAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
}
Problem:
dj-rest-auth
login sets JWTs in HTTP-only cookies, but registration does not — it only returns tokens in the response body.
Cause:
RegisterView
doesn’t include the logic to set cookies like LoginView
does.
To Fix: - To set JWT cookies on registration (just like login), extend RegisterView
and manually set the cookies.
Create a custom RegisterView
:
# views.py:
from dj_rest_auth.registration.views import RegisterView
from dj_rest_auth.jwt_auth import set_jwt_cookies
from rest_framework import status
class CustomRegisterView(RegisterView):
def create(self, request, *args, **kwargs):
response = super().create(request, *args, **kwargs)
if response.status_code == status.HTTP_201_CREATED:
access = response.data.get("access")
refresh = response.data.get("refresh")
if access and refresh:
set_jwt_cookies(response, access, refresh)
return response
# urls.py:
from .views import CustomRegisterView
urlpatterns = [
path("auth/register/", CustomRegisterView.as_view(), name="custom_register"),
]