pythonpython-3.xdjangomiddlewaredjango-middleware

How to resolve missing 1 required positional argument: 'get_response' in Django


I am new to Django and I want to add a Middleware for JWT Authentication. I am using Django version 4.2.6 My Middleware code is as follows:

import jwt
from django.http import JsonResponse
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin


class TokenMiddleware(MiddlewareMixin):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Check if the request has an "Authorization" header
        authorization = request.META.get('HTTP_AUTHORIZATION')

        if authorization and authorization.startswith('Bearer '):
            token = authorization.split(' ')[1]

            jwks_client = jwt.PyJWKClient(settings.JWT_VERIFY_URL)
            header = jwt.get_unverified_header(token)
            key = jwks_client.get_signing_key(header["kid"]).key
            
            try:
                jwt.decode(token, key, [header["alg"]])

            except jwt.ExpiredSignatureError:
                return JsonResponse({'error': 'Token has expired'}, status=401)

            except jwt.DecodeError:
                return JsonResponse({'error': 'Token is invalid'}, status=401)
        else:
            return JsonResponse({'message': 'Authentication Bearer Token is required.'})

        response = self.get_response(request)
        return response

I have registered my Middleware in settings.py. I have been trying to fix this error but nothing really helped. It triggers when get_response is called. For this code I am getting the following error:

Traceback (most recent call last):
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/django/views/generic/base.py", line 104, in view
    return self.dispatch(request, *args, **kwargs)
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 492, in dispatch
    request = self.initialize_request(request, *args, **kwargs)
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 394, in initialize_request
    authenticators=self.get_authenticators(),
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 272, in get_authenticators
    return [auth() for auth in self.authentication_classes]
  File "/home/abdulai/projects/abdulai/holden/nyc-transactions/nyc-transactions-backend/venv/lib/python3.10/site-packages/rest_framework/views.py", line 272, in <listcomp>
    return [auth() for auth in self.authentication_classes]
TypeError: TokenMiddleware.__init__() missing 1 required positional argument: 'get_response'
[14/Oct/2023 14:10:41] "GET /user/ HTTP/1.1" 500 95495

I have registered my Middleware in settings.py in the following way.

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "my_app.middleware.TokenMiddleware",
    "corsheaders.middleware.CorsMiddleware",
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'my_app.middleware.TokenMiddleware',
    ],
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        # Add other renderers as needed
    ]
    # Other DRF settings...
}

Solution

  • YOu should not use the MiddlewareMixin, the MiddlewareMixin is for the old-style middleware, but you are writing this in the new way, so:

    class TokenMiddleware:  # !L! no MiddlewareMixin
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            authorization = request.META.get('HTTP_AUTHORIZATION')
            if authorization and authorization.startswith('Bearer '):
                token = authorization.split(' ')[1]
                jwks_client = jwt.PyJWKClient(settings.JWT_VERIFY_URL)
                header = jwt.get_unverified_header(token)
                key = jwks_client.get_signing_key(header['kid']).key
                try:
                    jwt.decode(token, key, [header['alg']])
                except jwt.ExpiredSignatureError:
                    return JsonResponse({'error': 'Token has expired'}, status=401)
                except jwt.DecodeError:
                    return JsonResponse({'error': 'Token is invalid'}, status=401)
            else:
                return JsonResponse(
                    {'message': 'Authentication Bearer Token is required.'}
                )
            return self.get_response(request)

    As for the DRF, your TokenMiddleware is not an authentication class, but likely not necessary here anyway, since it will go through the middleware. You thus remove this from the AUTHENTICATION_CLASSES:

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            # 'my_app.middleware.TokenMiddleware',  # 🖘 remove
        ],
        # …
    }