DRF auth_token: "non_field_errors": [ "Unable to log in with provided credentials."

codyc4321 picture codyc4321 · Oct 17, 2016 · Viewed 16k times · Source

Both JWT packages written for Django gave me issues with poor documentation, so I try DRF-auth_token package. This is a good example I followed, Django Rest Framework Token Authentication. You should in theory be able to go to

localhost:8000/api-token-auth/

urls.py:

from django.conf.urls import url, include
from django.contrib import admin
from django.contrib.auth.models import User
from rest_framework.authtoken import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls', namespace='api')),
    url(r'^orders/', include('orders.urls', namespace='orders')),
    url(r'^api-token-auth/', views.obtain_auth_token, name='auth-token'),

]

Getting a token for users is not working so I have rewritten it myself to make it work:

@api_view(['POST'])
def customer_login(request):
    """
    Try to login a customer (food orderer)
    """
    data = request.data

    try:
        username = data['username']
        password = data['password']
    except:
        return Response(status=status.HTTP_400_BAD_REQUEST)

    try:
        user = User.objects.get(username=username, password=password)
    except:
        return Response(status=status.HTTP_401_UNAUTHORIZED)

    try:
        user_token = user.auth_token.key
    except:
        user_token = Token.objects.create(user=user)

    data = {'token': user_token}
    return Response(data=data, status=status.HTTP_200_OK)

My version works:

http://localhost:8000/api/login/customer-login/
{"username": "[email protected]", "password": "wombat"}
-->
{
  "token": "292192b101153b7ced74dd52deb6b3df22ef2c74"
}

The DRF auth_token does not work:

http://localhost:8000/api-token-auth/
{"username": "[email protected]", "password": "wombat"}
-->
{
  "non_field_errors": [
    "Unable to log in with provided credentials."
  ]
}

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # third party:
    'django_extensions',
    'rest_framework',
    'rest_framework.authtoken',



REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    )
}

It seems set up correctly. Every user in my DB has a token. Each user is is_authenticated and is_active in DB. Super users can get their token:

localhost:8000/api-token-auth/
{"username": "mysuperuser", "password": "superuserpassword"}
-->
{
  "token": "9297ff1f44dbc6caea67bea534f6f7590d2161b0"
}

for some reason, only super user can get a token:

localhost:8000/api-token-auth/
{"username": "regularguy", "password": "password"}
-->
{
  "non_field_errors": [
    "Unable to log in with provided credentials."
  ]
}

Why can't my users log in and get their token? Thank you

Answer

rawand deheliah picture rawand deheliah · Nov 13, 2019
  • I had the same error message when I tried to use this API endpoint :
    " obtain_auth_token" class from rest_framework.authtoken.views ,
    BUT surprise ! The problem was the User serializer in first place ! .

  • Users were created with the API endppint ,their passwords were saved as plain text !, as in this screenshot : User Database
    BUT the TokenAPI endpoint encrypts the password, so from there come the clash! ,

  • I've changed User Serializer class and override create function to use set_password function that hashes the passwords :

    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = User
            fields = ['email', 'username', 'password']
            extra_kwargs = {'password': {'write_only': True}}
    
        def create(self, validated_data):
            user = User(
                email=validated_data['email'],
                username=validated_data['username']
            )
            user.set_password(validated_data['password'])
            user.save()
            return user
    
  • Now that I've edited my User Serializer , data are stored like this : User database after modification

  • And So the error : “non_field_errors”: [ “Unable to log in with provided credentials.” stopped showing ! , and the token API endpoint "localhost:8000/api-token-auth/" worked !