2

I have implemented token based authentication using rest_framework, every thing is working fine as of now but I have one question that if I am sending user-name and password in header using basic-auth then why am I required to send user-name and password with payload. When I sending request containing payload with user-name and password in body section with out user-name and password in header of request, I am getting following as response:

{
  "detail": "CSRF Failed: CSRF token missing or incorrect."
}

while I am sending user-name and password in header with out sending user-name and password with payload, I am getting following response:

{
  "detail": "Invalid username/password."
}

Why am I required to send user-name and password in header section while I am sending it with payload. I am not quite sure about the concept. Could anyone please explain and show me the right way to do it. I have used this reference.

Following is my code: authuser.py

"""Authentication classes for Django Rest Framework.
Classes:
    ExpiringTokenAuthentication: Authentication using extended authtoken model.
"""

from rest_framework import exceptions
from rest_framework.authentication import TokenAuthentication

from rest_framework_expiring_authtoken.models import ExpiringToken


class ExpiringTokenAuthentication(TokenAuthentication):

    """
    Extends default token auth to have time-based expiration.
    Based on http://stackoverflow.com/questions/14567586/
    """

    model = ExpiringToken

    def authenticate_credentials(self, key):
        """Attempt token authentication using the provided key."""
        if key == "2572e6dbe3b2e150764cd72712713b2975785197":
            token = self.model.objects.get(key=key)
        else:
            try:
                token = self.model.objects.get(key=key)
            except self.model.DoesNotExist:
                raise exceptions.AuthenticationFailed('Invalid token')

            if not token.user.is_active:
                raise exceptions.AuthenticationFailed('User inactive or deleted')

            #if token.expired():
             #   raise exceptions.AuthenticationFailed('Token has expired')

        return (token.user_id, token)

view .py

 class ObtainExpiringAuthToken(ObtainAuthToken):

    """View enabling username/password exchange for expiring token."""
    model = ExpiringToken
    def post(self, request):
        try:
            payload=json.loads(request.body)
        except:
            return Response({'success':False,'message':'Invalid Payload.'})
        """Respond to POSTed username/password with token."""
        serializer = AuthTokenSerializer(data=request.data)
        if serializer.is_valid():
            token, _ = ExpiringToken.objects.get_or_create(
                user=serializer.validated_data['user']
            )
            if token.expired():
                # If the token is expired, generate a new one.
                token.delete()
                token = ExpiringToken.objects.create(
                    user=serializer.validated_data['user']
                )

            try:
                user = User.objects.get(id=token.user_id)
            except:
                return Response({'success':False,'message':'User does not exists.'})
    return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()

models.py :

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance)

class ExpiringToken(Token):

    """Extend Token to add an expired method."""

    class Meta(object):
        proxy = True

    def expired(self):
        """Return boolean indicating token expiration."""
        now = timezone.now()
        #if self.created < now - token_settings.EXPIRING_TOKEN_LIFESPAN:
         #   return True
        return True

settings.py:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework.parsers.JSONParser',
    )
}
Anuj Masand
  • 359
  • 1
  • 4
  • 16
  • Are you confused on why you're getting the CRSF-token error? Or do you want to know why you have to send a CSRF-token? If you're using a view with a template to do the call you have to put `{% csrf_token %}` inside the form. – Bono Jun 24 '17 at 11:09
  • @Bono yes, I need to know why am I getting CRSF-token error? I am just developing a API so I don't require a template. When ever I am sending user-name and password both in Header section and with in payload, i am getting desired response. I just want to send credentials either in payload or header. – Anuj Masand Jun 24 '17 at 12:43
  • @AnujMasand Where/how do you set `ExpiringTokenAuthentication`? – mariodev Jun 25 '17 at 04:38
  • Are you not getting the token when you log in, why are you sending username and password everytime with the payload, you just need to send the generated token in the header. I mean, what's the point of token authentication, if you are not utilising it. When you send username and password in your header, you are authenticating via BasicAuthentication, not TokenAuthentication. Put the generated token during login in the headers until log out and play along with the transactions. – zaidfazil Jun 26 '17 at 07:18
  • @Fazil Zaid, Thanks for passing by. You are close. Fazil i am just using this once and afterwards i'll use the token that i have returned with payload. I understand your point. What i am seeking is that, While using Basic Auth why do i need to send username and password with the payload. – Anuj Masand Jun 26 '17 at 08:06

1 Answers1

0

The only possible way to get this error is by having SessionAuthentication enabled. It's enabled globally by default.

http://www.django-rest-framework.org/api-guide/authentication/#setting-the-authentication-scheme

Please double check you settings or set a proper one in you view class to override the global one.

mariodev
  • 13,928
  • 3
  • 49
  • 61