'Django - DRF - Authentication credentials were not provided. - just in Production. What is the cause?

Problem

During the deployment of my backend API to Heroku trough Docker container I encounter the following error with status 403(Forbidden) whenever I try to access some data where the user has to be authenticated:

{
    "detail": "Authentication credentials were not provided."
}

In development everything works as expected.

I am aware of the similar question Django Rest Framework - Authentication credentials were not provided. However here the solution is connected with Apache configuration, which strips the AUTHENTICATION header.

During the debugging of the issue I found out, the AUTHENTICATION header is available for the application, and in fact the token can be obtained and read without any issue.

As a test I have written my own permission class where I have found out, the request.user.is_authenticated line in development gives True but in production gives False with the exact same data and test case.

class AuthOrReadOnly(BasePermission):
    def has_permission(self, request, view):
        print(request.user.is_authenticated)
        if request.method in permissions.SAFE_METHODS:
            return True
        if request.user.is_authenticated:
            return True

        return False

SOLUTION to the problem itself

I needed to add authentication_classes = (JWTAuthentication,) for my each APIview class where I need to access authenticated content.

Example:

class RegistrationsForUserView(APIView):
    permission_classes = [
        permissions.IsAuthenticatedOrReadOnly,
    ]
    authentication_classes = (JWTAuthentication,)
    serializer_class = RegistrationSerializerForUser

    def get(self, request, pk, format=None):
        registrations = Registration.objects.filter(user=pk).order_by(
            "tournament__event_date"
        )
        serializer = RegistrationSerializerForUser(registrations, many=True)
        return Response(serializer.data, status.HTTP_200_OK)

In settings.py I have the following regarding REST_FRAMEWORK:

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "rest_framework_simplejwt.authentication.JWTAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ),
}

Question

What is the cause of different behavior in production compared to development? What am I missing? In the documentation of DRF the authentication_classes seems to be optional not mandatory. But even if it would be mandatory, I would expect the same behavior in production.



Solution 1:[1]

SOLUTION to the problem itself

I needed to add authentication_classes = (JWTAuthentication,) for my each APIview class where I need to access authenticated content.

Example:

class RegistrationsForUserView(APIView):
    permission_classes = [
        permissions.IsAuthenticatedOrReadOnly,
    ]
    authentication_classes = (JWTAuthentication,)
    serializer_class = RegistrationSerializerForUser

    def get(self, request, pk, format=None):
        registrations = Registration.objects.filter(user=pk).order_by(
            "tournament__event_date"
        )
        serializer = RegistrationSerializerForUser(registrations, many=True)
        return Response(serializer.data, status.HTTP_200_OK)

In settings.py I have the following regarding REST_FRAMEWORK:

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "rest_framework_simplejwt.authentication.JWTAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ),
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MatyasM