2025, Oct 17 23:00

How to make dj-rest-auth registration set JWT HTTP-only cookies in Django REST Framework

Fix dj-rest-auth mismatch: make registration set JWT HTTP-only cookies like login. Guide for DRF/allauth to keep signup and sign-in flows consistent. Secure.

When wiring up authentication in Django REST Framework with dj-rest-auth and django-allauth using JWT, it’s common to rely on HTTP-only cookies for token storage. The built-in login endpoint already behaves this way, setting cookies for access and refresh tokens. The surprise comes at registration time: the default registration endpoint returns tokens only in the response body and does not set JWT cookies. Below is a focused guide to align registration with login so both issue JWTs via HTTP-only cookies.

What’s going wrong

The login endpoint from dj_rest_auth automatically sets JWTs in HTTP-only cookies and also returns the access token in the response body. The registration endpoint, by contrast, returns access and refresh tokens in the response body only and does not attach them as cookies. If your frontend expects the same cookie-based token flow after sign-up as after sign-in, this inconsistency becomes a real integration issue.

Minimal example that shows the mismatch

Using the stock registration view produces the behavior described above — tokens land in the response body only, not in cookies.

# urls.py
from django.urls import path
from dj_rest_auth.registration.views import RegisterView as SignupBaseView
urlpatterns = [
    path("auth/register/", SignupBaseView.as_view(), name="register"),
]

Why this happens

The registration view does not include the cookie-setting logic that the login view has. In other words, RegisterView doesn’t set JWT cookies; LoginView does. That’s the entire reason for the discrepancy.

How to make registration set HTTP-only cookies too

Extend the registration view and explicitly set cookies on a successful sign-up. The idea is simple: call the parent create(), check for a 201 response, read access and refresh tokens from the response payload, and apply set_jwt_cookies.

# views.py
from dj_rest_auth.registration.views import RegisterView
from dj_rest_auth.jwt_auth import set_jwt_cookies as bind_jwt_cookies
from rest_framework import status as http_status
class SignupCookieView(RegisterView):
    def create(self, request, *args, **kwargs):
        reply = super().create(request, *args, **kwargs)
        if reply.status_code == http_status.HTTP_201_CREATED:
            token_access = reply.data.get("access")
            token_refresh = reply.data.get("refresh")
            if token_access and token_refresh:
                bind_jwt_cookies(reply, token_access, token_refresh)
        return reply
# urls.py
from django.urls import path
from .views import SignupCookieView
urlpatterns = [
    path("auth/register/", SignupCookieView.as_view(), name="signup_with_cookies"),
]

A quick note on “why not by default?”

The practical answer is that the registration view simply doesn’t include the cookie-setting path that the login view implements. Rather than relying on implicit coupling between registration and login flows, this approach makes the behavior explicit by overriding the registration view and setting cookies yourself.

Why this detail matters

Consistency between sign-up and sign-in flows reduces edge cases on the client and helps you adhere to a cookie-based JWT handling model end-to-end. If your application strategy is to keep tokens in HTTP-only cookies, having registration align with login prevents special-case logic for first-time users and avoids exposing the refresh token anywhere other than where you intend it to be.

Wrap-up

Keep the user journey uniform: after login and after registration, the client should end up with the same authentication state. With dj-rest-auth and django-allauth, that means extending the registration view so that it sets JWT cookies on successful account creation. The change is minimal, but it removes friction in your client code and aligns your endpoints with the cookie-based JWT approach you’ve chosen.

The article is based on a question from StackOverflow by Sebastian Power and an answer by Razia Khan.