Search code examples
djangopython-3.xdjango-rest-frameworkjwtdjango-rest-framework-simplejwt

Django Rest Framework avoid authentication JWT


I am using rest_framework_simplejwt to authenticate my users but, in some views i need to ignore it, because these are public views. i want to check the token into view flow. The expected behaviour is:

In public view

  • Avoid token validation: If is there an expired or invalid token, ignore it and let me in to validate it into APIView

Actually rest_framework_simplejwt checks token and raise 401 if token is invalid or expired...

I tried disabling authentication_classes within APIView like this:

class SpecificProductApi(APIView):

    def get_authenticators(self):
        if self.request.method == 'GET':
            self.authentication_classes = []
        return super(SpecificProductApi, self).get_authenticators()

but if i disable it before enter GET APIView method, i can't do if reques.user.is_authenticated: because I disabled the token :(

Exists a way to enable entering to api http method and check users manually into view? thanks


Solution

  • Have a very similar problem. To create public endpoints you are forced to override the authenticators, or else you will return 401/403 on expired/missing token.

    However, a public endpoint does not mean that it should not have authentication. Rather it should have one response for no-auth / expired-auth and another for valid auth.

    I don't know if this is the "correct" way, but this is what I came up with facing the same problem.

    Override the authenticators as you have done, and add an additional method to validate the authenticators in your view.

    For example:

    class SomeApiView(APIView):
        def get_authenticators(self):
            # Override standard view authenticators.
            # Public endpoint, no auth is enforced.
            return []
    
        def get_auth(self):
            # Return a generator of all authenticators.
            return (auth() for auth in self.authentication_classes)
    
        def get_auth_detail(self, request):
            # Evaluate each authenticator and return the first valid authentication.
            for auth in self.get_auth():
                # You probably need try / except here to catch authenticators 
                # that are invalid (403/401) in the case of multiple authentication 
                # classes--such as token auth, session auth, etc...
                auth_detail = auth.authenticate(request)
                if auth_detail:
                    return auth_detail
    
            return None, None
    
        def post(self, request):
            # Returns a tuple of (User, JWT), can be (None, None)
            user, jwt = self.get_auth_detail(request)  
    
            # Do your magic based on user value.
            if user:
                # User is authenticated.
            else:
                # User is anon / not-authenticated.