Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 385
Jhon Sanz Avatar asked Dec 17 '19 13:12

Jhon Sanz


People also ask

Which authentication is best in Django REST framework?

And these are all provided by drf(django rest framework) and other than these like oauth, oauth2 based authentication are provided by the efforts of the community with help of other python packages. And they can be easily used in the production environment.

What is JWT authentication in Django REST framework?

Simple JWT provides a JSON Web Token authentication backend for the Django REST Framework. It aims to cover the most common use cases of JWTs by offering a conservative set of default features. It also aims to be easily extensible in case a desired feature is not present.

How JWT token works in Django REST framework?

After verifying the credentials, the server issues two JSON Web Tokens to the user. One of them is an Access Token and the other is a Refresh Token. The frontend of your application then stores the tokens securely and sends the Access Token in the Authorization header of all requests it then sends to the server.


3 Answers

I get it done by adding authentication_classes = []

from rest_framework import permissions

class SpecificProductApi(APIView):
    permission_classes = [permissions.AllowAny]
    authentication_classes = []
like image 123
Franco Nisi Avatar answered Oct 09 '22 20:10

Franco Nisi


You could simply use authentication_classes = [] in the view, but this always bypasses the JWT authentication, even when a valid Authorization-header with the token is present. You'd better extend the JWTAuthentication-class as follows (similar to the comment of Jhon Edwin Sanz Gonzalez):

from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken


class JWTAuthenticationSafe(JWTAuthentication):
    def authenticate(self, request):
        try:
            return super().authenticate(request=request)
        except InvalidToken:
            return None

Then use authentication_classes = [JWTAuthenticationSafe] in your view.

like image 34
Neman Avatar answered Oct 09 '22 20:10

Neman


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.
like image 37
James Avatar answered Oct 09 '22 21:10

James