Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Login Error Messages for Unverified Email Addresses in Djoser #738

Open
kotaamo opened this issue May 31, 2023 · 1 comment
Open

Login Error Messages for Unverified Email Addresses in Djoser #738

kotaamo opened this issue May 31, 2023 · 1 comment

Comments

@kotaamo
Copy link

kotaamo commented May 31, 2023

Dear Djoser Community,

I'm implementing login authentication in my application using Djoser.
Currently, a user creates an account by inputting their email address and password, and then completes the verification process by clicking the verification link sent to their email address.

I would like to enhance the user experience by sending a specific error message, something like "Email address is not verified", when a user attempts to login without having completed email verification.

Looking at the djoser/serializers.py, I noticed that when a user tries to login with an unverified email address, the same error message is returned as if it were a simple login error.

def validate(self, attrs):
    password = attrs.get("password")
    params = {settings.LOGIN_FIELD: attrs.get(settings.LOGIN_FIELD)}
    self.user = authenticate(
        request=self.context.get("request"), **params, password=password
    )
    if not self.user:
        self.user = User.objects.filter(**params).first()
        if self.user and not self.user.check_password(password):
            self.fail("invalid_credentials")
    if self.user and self.user.is_active:
        return attrs
    self.fail("invalid_credentials")

With this current implementation, whether the user input incorrect account details or they have not completed the email verification, both cases will return the "invalid_credentials" error message, which is defined as "No active account found with the given credentials".

Here are my questions:

Is it acceptable to modify the above validate function to display to the user that the authentication has not been completed when an unverified email user tries to log in?

I believe I could modify the validate function as shown below to distinguish between the two error cases, but I'm curious if there are reasons for not implementing it this way or if there are any risks involved:

  • Return "inactive_account" error instead of "invalid_credentials" error only when self.user.is_active is False. This way, I believe I could differentiate between the case where the user inputted wrong account details and the case where the user has not completed email verification.

In TokenCreateSerializer, INACTIVE_ACCOUNT_ERROR is defined as the error message for the case where account authentication has not been completed. Is there any particular reason why this is not being invoked?

default_error_messages = { "invalid_credentials": settings.CONSTANTS.messages.INVALID_CREDENTIALS_ERROR, "inactive_account": settings.CONSTANTS.messages.INACTIVE_ACCOUNT_ERROR, }

Any guidance would be greatly appreciated.
Thank you in advance for your help.

Best regards,
Kota Amo

@tomwojcik
Copy link
Contributor

tomwojcik commented Mar 31, 2024

Is it acceptable to modify the above validate function to display to the user that the authentication has not been completed when an unverified email user tries to log in?

One reason for using a generic "invalid_credentials" error message is to avoid giving away too much information about the account's state, which could potentially be used maliciously. For example, confirming that an email address is registered but not activated could be seen as a privacy leak.

Return "inactive_account" error instead of "invalid_credentials" error only when self.user.is_active is False. This way, I believe I could differentiate between the case where the user inputted wrong account details and the case where the user has not completed email verification.

    def validate(self, attrs):
        password = attrs.get("password")
        params = {settings.LOGIN_FIELD: attrs.get(settings.LOGIN_FIELD)}
        self.user = authenticate(request=self.context.get("request"), **params, password=password)
    
        if not self.user:
            self.user = User.objects.filter(**params).first()
            if self.user and not self.user.check_password(password):
                self.fail("invalid_credentials")
    
        if self.user and not self.user.is_active:
            self.fail("inactive_account")
    
        if self.user:
            return attrs
    
        self.fail("invalid_credentials")

That does make sense. I'd be willing to accept a PR with these changes, but by default inactive_account needs to fail with the same error message as invalid_credentials.

In TokenCreateSerializer, INACTIVE_ACCOUNT_ERROR is defined as the error message for the case where account authentication has not been completed. Is there any particular reason why this is not being invoked?

It seems to be a leftover from the ancient times.

if django.VERSION >= (1, 10):
expected_errors = [settings.CONSTANTS.messages.INVALID_CREDENTIALS_ERROR]
else:
expected_errors = [settings.CONSTANTS.messages.INACTIVE_ACCOUNT_ERROR]

EDIT: I removed it b02c422

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants