Django with DRF. Users cannot sign in with their credentials

Question:

I have a web app using Django as the backend and React as the frontend. I have a sign up form where the users enter their credentials and the profile is created in the database. However, when the users create their profile, they are unable to login even though the user data is available in the database. Altering the user password with the django-admin panel fixes this issue and the users can login sucessfully into their accounts. I’m assuming this is an issue with the password saving during profile creation but I can find the issue.

Profile creation method

# Create user
@api_view(['POST'])
def sign_up(req):
    serializer = UserSerializer(data=req.data)

    if serializer.is_valid():
        if User.objects.filter(email=serializer.validated_data['email']).exists():
            return Response({'email': 'The email entered is already in use by another account.'})

        serializer.save()
        return Response({'status': 'success'})

    else:
        return Response(serializer.errors)

User sign in method

# Sign in user
@api_view(['POST'])
def sign_in(req):
    username = req.data['username']
    password = req.data['password']

    user = authenticate(req, username=username, password=password)

    if user is not None:
        return Response({'status': 'success'})

    else:
        return Response({'err': 'The username or password entered is incorrect.nThe username and password are case sensitive.'})

Here is the UserSerializer.

class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

I have tried forcefully resaving the password on profile creation but that doesn’t work. Have also tried some online solutions but to no avail.

Asked By: Charles

||

Answers:

You no need to pass req in authenticate method

# Sign in user
@api_view(['POST'])
def sign_in(req):
    username = req.data['username']
    password = req.data['password']

    user = authenticate(username=username, password=password)

The problem is that the password is being passed in raw, by default django does not store it and sets the password as invalid. What you need is to override the serializer creation method and hash the password manually:

from rest_framework.serializers import ModelSerializer
from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password

class UserSerializer(ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = '__all__'

    def create(self, validated_data):
        instance = get_user_model()(
            username=validated_data['username'],
            password=make_password(validated_data['password']),
            email=validated_data['email'],
            is_staff=True,
            is_active=True
        )
        instance.save()
        
        return instance
Answered By: Niko