Search code examples
djangodjango-rest-frameworkrefresh-tokendjango-rest-framework-simplejwtcookie-httponly

DRF simplejwt refresh access_token stored in HTTPonly cookies


I'm doing a project using React and django, I have used a DRF SimpleJWT for authentication. I have stored a access and refresh token in HTTPOnly cookies all are working fine but I didn't find the way to refresh the token. I can't make it through by reading a documentation. If somebody has done it before please share the code


Solution

  • Hope I'm not late.
    An easy way, you can use Dj-Rest-Auth to handle everything.

    Otherwise, If you want to use function views you can use in your views.py and add its URL to urls.py:

    @api_view(['POST'])
    @permission_classes([AllowAny])
    @csrf_protect
    def refresh_token_view(request):
        User = get_user_model()
        refresh_token = request.COOKIES.get('refreshtoken')
        if refresh_token is None:
            raise exceptions.AuthenticationFailed(
                'Authentication credentials were not provided.')
        try:
            payload = jwt.decode(
                refresh_token, settings.REFRESH_TOKEN_SECRET, algorithms['HS256'])
        except jwt.ExpiredSignatureError:
            raise exceptions.AuthenticationFailed(
                'expired refresh token, please login again.')
    
        user = User.objects.filter(id=payload.get('user_id')).first()
        if user is None:
            raise exceptions.AuthenticationFailed('User not found')
    
        if not user.is_active:
            raise exceptions.AuthenticationFailed('user is inactive')
    
    
        access_token = generate_access_token(user)
        return Response({'access_token': access_token})
    

    If you want to use class views add this to your views.py:

    from rest_framework_simplejwt.views import TokenRefreshView, TokenObtainPairView
    from rest_framework_simplejwt.serializers import TokenRefreshSerializer
    from rest_framework_simplejwt.exceptions import InvalidToken
    
    class CookieTokenRefreshSerializer(TokenRefreshSerializer):
        refresh = None
        def validate(self, attrs):
            attrs['refresh'] = 
    self.context['request'].COOKIES.get('refresh_token')
            if attrs['refresh']:
                return super().validate(attrs)
            else:
                raise InvalidToken('No valid token found in cookie\'refresh_token\'')
    
    class CookieTokenObtainPairView(TokenObtainPairView):
        def finalize_response(self, request, response, *args, **kwargs):
            if response.data.get('refresh'):
                cookie_max_age = 3600 * 24 * 14 # 14 days
                response.set_cookie('refresh_token',response.data['refresh'],max_age=cookie_max_age, httponly=True )
            del response.data['refresh']
            return super().finalize_response(request, response, *args, **kwargs)
    
    class CookieTokenRefreshView(TokenRefreshView):
        def finalize_response(self, request, response, *args, **kwargs):
            if response.data.get('refresh'):
                cookie_max_age = 3600 * 24 * 14 # 14 days
                response.set_cookie('refresh_token',response.data['refresh'], max_age=cookie_max_age, httponly=True )
            del response.data['refresh']
            return super().finalize_response(request, response, *args, **kwargs)
        serializer_class = CookieTokenRefreshSerializer
    

    Add the below in url.py to use the above views to get and refresh:

    from .views import CookieTokenRefreshView, CookieTokenObtainPairView # Import the above views
    urlpatterns = [
    path('auth/token/', CookieTokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('auth/token/refresh/', CookieTokenRefreshView.as_view(), name='token_refresh'),
    ]
    

    source