django-rest-framework using HttpOnly Cookie

I've added this middleware to my Django (3.1):

class YankTokenRefreshFromHeaderIntoTheBody(MiddlewareMixin):
    """
    for Django Rest Framework JWT's POST "/token-refresh" endpoint --- check for a 'token' in the request.COOKIES
    and if, add it to the body payload.
    """

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, *view_args, **view_kwargs):
        if request.path == '/v1/token-refresh' and 'token' in request.COOKIES:
            data = json.loads(request.body)
            data['token'] = request.COOKIES['token']
            request._body = json.dumps(data).encode('utf-8')
        return None

Then I added it here in my settings:

MIDDLEWARE = [
    'myproj.utils.middleware.YankTokenRefreshFromHeaderIntoTheBody',
    ...
    ...
]

And that's it. Django REST framework JWT's token-refresh endpoint will now work as it will find the 'token' key/value in there.

Few things to note:

  1. I chose 'token' as the name of the cookie holding tte JWT token. Yours may vary of course.
  2. I changed the endpoint's name to /v1/token-refresh -- You'd need to change that too if you are using the original named endpoint.

The issue that you observe is correct as the refresh token api has not been implemented with the cookies.

This could be a bug in the code itself. But nothing restrict you from fixing this issue.

You can patch the view to take care of cookie based auth as well. Add below code to the top of your urls.py and it will take care of the same

from rest_framework_jwt.settings import api_settings

if api_settings.JWT_AUTH_COOKIE:
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from rest_framework_jwt.serializers import RefreshJSONWebTokenSerializer
    from rest_framework_jwt.views import RefreshJSONWebToken

    RefreshJSONWebTokenSerializer._declared_fields.pop('token')

    class RefreshJSONWebTokenSerializerCookieBased(RefreshJSONWebTokenSerializer):
        def validate(self, attrs):
            if 'token' not in attrs:
                if api_settings.JWT_AUTH_COOKIE:
                    attrs['token'] = JSONWebTokenAuthentication().get_jwt_value(self.context['request'])
            return super(RefreshJSONWebTokenSerializerCookieBased, self).validate(attrs)

    RefreshJSONWebToken.serializer_class = RefreshJSONWebTokenSerializerCookieBased

Refresh working with cookies