djangorestframework-simplejwt icon indicating copy to clipboard operation
djangorestframework-simplejwt copied to clipboard

TokenBlacklistView should require access token

Open Chhunneng opened this issue 1 year ago • 9 comments

as we use TokenBlacklistView to log out users but I recognize that it does not require an access token to log out. I think It should.

Chhunneng avatar Jun 13 '23 04:06 Chhunneng

Agree, I have implemented this in my own APIView this way:

class Logout(APIView):
    """
    The API for logging out a user -> blacklisting tokens
    """
    permission_classes = (IsAuthenticated, )
    serializer_class = LogoutSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        return self.valid_request_data(serializer.validated_data, request)

    def valid_request_data(self, data, request):
        refresh_token = data["refresh_token"]
        user = request.user

        with transaction.atomic():
           user.blacklist_token(refresh_token)

        return ApiMessageResponse(_("Logged out succesfully"), status=status.HTTP_200_OK)

tpotjj avatar Jun 29 '23 12:06 tpotjj

Agree, I have implemented this in my own APIView this way:

class Logout(APIView):
    """
    The API for logging out a user -> blacklisting tokens
    """
    permission_classes = (IsAuthenticated, )
    serializer_class = LogoutSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        return self.valid_request_data(serializer.validated_data, request)

    def valid_request_data(self, data, request):
        refresh_token = data["refresh_token"]
        user = request.user

        with transaction.atomic():
           user.blacklist_token(refresh_token)

        return ApiMessageResponse(_("Logged out succesfully"), status=status.HTTP_200_OK)

Can I ask user.blacklist_token(refresh_token), Do the users have this function auto or need to override? And can I see your LogoutSerializer?

Chhunneng avatar Jun 30 '23 00:06 Chhunneng

The blacklist_token is a method that I added to the User model (class) myself:

    def blacklist_token(self, token):
        outstanding_token = OutstandingToken.objects.get(token=token)
        BlacklistedToken.objects.create(token=outstanding_token)

And here is the LogoutSerializer:

class LogoutSerializer(serializers.Serializer):
    refresh_token = serializers.CharField(allow_blank=False)

Nothing special actually, pretty basic APIView and Serializer :)

tpotjj avatar Jun 30 '23 04:06 tpotjj

The blacklist_token is a method that I added to the User model (class) myself:

    def blacklist_token(self, token):
        outstanding_token = OutstandingToken.objects.get(token=token)
        BlacklistedToken.objects.create(token=outstanding_token)

And here is the LogoutSerializer:

class LogoutSerializer(serializers.Serializer):
    refresh_token = serializers.CharField(allow_blank=False)

Nothing special actually, pretty basic APIView and Serializer :)

After add refresh token to blacklist, the access token is still usable!

Chhunneng avatar Jun 30 '23 06:06 Chhunneng

@Chhunneng correct, but only for the time it is issued with, which is a configuration you can manage yourself. I've set this to 1min, which means that the client has a maximum of 60 seconds to make requests with the access token they have.

Since the client, in my case a Vue/Nuxt application, I have control over the cookies & local storage. If a user presses log-out, we both delete all the tokens on the client, as well as blacklist the refresh token.

Since JWT is created with a stateless idea in mind, this would be the furthest I want to go personally. Otherwise, you could just use the built-in Django Authentication system with the Token system they provide out of the box.

Maybe it would be good to have a look at this issue: https://github.com/jazzband/djangorestframework-simplejwt/issues/371

tpotjj avatar Jun 30 '23 08:06 tpotjj

I want to ask if your login method was rewritten by yourself, not using Djangos built-in login, but I used the login that Djangos own, I used your method to set the usermodel, as the user logout, It reports the error "OutstandingToken matching query does not exist.", which looks like the 'OutstandingToken' object does not exist, causing it to report an error

expzhizhuo avatar Aug 19 '23 17:08 expzhizhuo

@zhizhuoshuma I have created my own logic regarding login and authentication. Providing a user with the JWT token is done with refresh = RefreshToken.for_user(self)

Now, copy/pasting everything here is a little bit redundant, so I would rather drop a link to my Repo here which you can use to figure out the missing parts: https://github.com/QuantTrade-io/qt-api

Under qt_auth -> views.py -> Line 161, you'll find the actual Login API endpoint.

If you have any further questions, feel free to ask them, I'm glad to help you out!

tpotjj avatar Aug 19 '23 20:08 tpotjj

Thank you very much. I have seen it. Do you have wechat? Can we add a friend? Look forward to your reply

expzhizhuo avatar Aug 20 '23 12:08 expzhizhuo

@zhizhuoshuma I don't have WeChat, I do have Telegram or Twitter: https://twitter.com/tpotjj

tpotjj avatar Aug 20 '23 18:08 tpotjj