I'm finding hard to figure out how to return 401 when the token has been deleted in database for whatever reason.
Let me explain.
My general settings use SessionAuthentication and TokenAuthentication schemes.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_FILTER_BACKENDS': (
'rest_framework.filters.DjangoFilterBackend',
),
'DATETIME_FORMAT': '%a, %d %b %Y %H:%M:%S %z',
'DATETIME_INPUT_FORMATS': ['iso-8601', '%Y-%m-%d %H:%M:%S', '%a, %d %b %Y %H:%M:%S %z'],
'DATE_FORMAT': '%Y-%m-%d',
'DATE_INPUT_FORMATS': ['%Y-%m-%d', '%m/%d/%YYYY'],
'PAGE_SIZE': 20
}
I have a view for generating the Auth Token, like this:
class AcmeObtainAuthToken(APIView):
throttle_classes = ()
permission_classes = ()
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
renderer_classes = (renderers.JSONRenderer,)
serializer_class = AcmeAuthTokenSerializer
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data)
serializer.context = {'request': self.request}
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key,
'school': school,
'user': user.id})
obtain_auth_token = AcmeObtainAuthToken.as_view()
My problem is that when token stored in db is gone for whatever reason and clients send the token, I'm getting 403, when I require 401.
Looking at the docs this is really cryptic:
The kind of response that will be used depends on the authentication scheme. Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. The first authentication class set on the view is used when determining the type of response.
It says it depends but how? No example is given...kinda confusing on how DRF does its magic under the hood here...
from django.contrib.auth import authenticate, login def my_view(request): username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) # Redirect to a success page. ... else: # Return an 'invalid ...
If you actually need JWTs, you should store them in a secure Cookie and they should have a very short TTL. The refresh token that allows you to refresh the JWT should be stored in a secure + HTTP only cookie. You should never store anything with personal or authentication related information in local storage.
403 is the response you should get in that instance. Have a look at this link:
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated.
In essence, the client made a correct request but the token is missing, therefore his access is forbidden (403).
If you really want to respond with a 401 error, you can try something like the following in your BloowatchObtainAuthToken
view:
class BloowatchObtainAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
response = super(BloowatchObtainAuthToken, self).post(request, *args, **kwargs)
try:
token = Token.objects.get(user=request.user) # or what you are validating against
other stuff here...
except Token.DoesNotExist:
return Response({'error': 'Token does not exist'}, status=401)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With