3

I'm trying to add an API using the Django REST framework to an existing codebase which uses the Django OAuth2 toolkit. The existing views make use of the fact that the OAuth2 toolkit's backend modifies the behavior of Django's login_required decorator so that it uses OAuth2 authentication. The function-based views look similar to the one in the tutorial example:

from django.contrib.auth.decorators import login_required
from django.http.response import HttpResponse

@login_required()
def secret_page(request, *args, **kwargs):
    return HttpResponse('Secret contents!', status=200)

I'm trying to adapt the example given on https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html to my situation, but I'm finding it's not an exact correspondence, because the example uses the DRF's ModelViewSet classes whereas my current view uses a (less-integrated) generic class-based view:

from rest_framework import generics

from ..models import Session
from ..serializers import SessionSerializer


class SessionDetail(generics.UpdateAPIView):
    queryset = Session.objects.all()
    serializer_class = SessionSerializer

where I've set the default permission class to IsAuthenticated in settings.py:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
}

This should allow a Session object to be updated using PATCH requests, but it appears to return a 403 Forbidden response for use cases similar to the ones for the current views decorated with login_required.

How can I update the SessionDetail view so that it behaves the same as a function view decorated with login_required? I suspect that I need to use the TokenHasReadWriteScope permission class, since this appears to be the only one for which the required_scopes is optional. (The views decorated with login_required don't provide required_scopes either).

Would it be like this:

from rest_framework import generics
from rest_framework.permissions import IsAuthenticated

from oauth2_provider.contrib.rest_framework import OAuth2Authentication, TokenHasReadWriteScope

from ..models import Session
from ..serializers import SessionSerializer


class SessionDetail(generics.UpdateAPIView):
    authentication_classes = [OAuth2Authentication]
    permission_classes = [TokenHasReadWriteScope]
    queryset = Session.objects.all()
    serializer_class = SessionSerializer

Also, would I have to update my REST_FRAMEWORK setting with a DEFAULT_AUTHENTICATION_CLASSES like this:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'oauth2_provider.contrib.rest_framework.OAuth2Authentication',
    )
}

Right now if I run the server and try to make a patch request with the browsable API, I get a 401 Unauthorized error:

enter image description here

Also if I Log in using a username and password that I just created using python manage.py createsuperuser, it goes straight back to this 401 page instead of one with a form to make a PATCH request as I'd expect.

Any ideas on how to fix this?

Kurt Peek
  • 52,165
  • 91
  • 301
  • 526

0 Answers0