djangoauthenticationdjango-rest-frameworktokendjango-authentication

Django returns "Authentication credentials were not provided" when I attempt token authentication


(I tried the solutions in similar questions, but they didn't work for me).

I am creating a simple Django REST based web-app, where a user will register, create some events, log in later and view events.

Here's the event's view:

class EventGetCreate(APIView):
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get(self, request):
        created_user = request.user
        events = Event.objects.filter(creator=created_user)
        serializer = EventSummary(events, many=True)
        return Response(serializer.data)

Its urls.py is as below:

from django.urls import path, include

from . import views

app_name = 'event'

urlpatterns = [
    ...
    path('eventviewall/', views.EventGetCreate.as_view()),
]

In core/urls.py, I have this to obtain the token:

from .views import UserViewSet
from rest_framework.authtoken.views import ObtainAuthToken, obtain_auth_token

app_name = 'core'

router = routers.DefaultRouter()
router.register('users', UserViewSet)

urlpatterns = [
    path('auth/', obtain_auth_token),
    path('register/', include(router.urls)),
]

Using postman, I can login successfully and get the token: Send request to http://127.0.0.1:8000/api/auth/ and get the following (example token):

{
    "token": "xxyyzz"
}

Now what I want to do is to send this token in a get request, and view the events the user created. I send the request to http://127.0.0.1:8000/event/eventviewall/, with the above token set in Authorization tab -> Bearer token.

However, I get the following response:

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

Now, if I set permission_classes = () in the view above (as suggested by some answers in similar questions), I get the following error:

TypeError at /event/eventviewall/
Field 'id' expected a number but got <django.contrib.auth.models.AnonymousUser object at 0x0000018BEF4573A0>.

I get that this error appears because Django sets the request.user to AnonymousUser as it cannot authenticate the user.

How do I fix this?


Solution

  • The problem is parsing the auth header (you're using an unexpected header value Bearer). The fix is to either change the value of the header, or change what value is expected (both are possible).

    Details directly from https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication:

    For clients to authenticate, the token key should be included in the Authorization HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example:

    Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
    

    If you want to use a different keyword in the header, such as Bearer, simply subclass TokenAuthentication and set the keyword class variable.