Skip to main content

Enforcing Password Validation

To ensure users choose strong, secure passwords, you can configure and use built-in validators that check for length, common patterns, and similarity to user information.

Configuring Password Validators

The primary way to enforce password security is by defining the AUTH_PASSWORD_VALIDATORS list in your settings.py file. Each entry in this list is a dictionary specifying the validator class and any optional parameters.

# settings.py

AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 10,
}
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]

Built-in Validator Classes

The following validators are available in django.contrib.auth.password_validation:

  • UserAttributeSimilarityValidator: Prevents passwords from being too similar to the user's attributes (username, first_name, last_name, and email). It uses difflib.SequenceMatcher to calculate a similarity ratio.
    • Options: user_attributes (tuple of attribute names, default: ('username', 'first_name', 'last_name', 'email')) and max_similarity (float between 0.1 and 1.0, default: 0.7).
  • MinimumLengthValidator: Ensures the password meets a minimum character count.
    • Options: min_length (integer, default: 8).
  • CommonPasswordValidator: Checks the password against a list of 20,000 common passwords stored in common-passwords.txt.gz.
  • NumericPasswordValidator: Rejects passwords that consist entirely of numeric digits.

Manually Validating Passwords

If you are building custom forms or API views, use the validate_password function to run a password through all configured validators.

from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError

def register_user(username, password):
# Create a temporary user object for attribute similarity checks
from django.contrib.auth.models import User
user = User(username=username)

try:
# This runs all validators defined in AUTH_PASSWORD_VALIDATORS
validate_password(password, user=user)
except ValidationError as e:
# e.messages contains a list of all validation error messages
print(f"Password invalid: {e.messages}")
return False

# Proceed with user creation
return True

In django/contrib/auth/forms.py, this pattern is used within form validation methods to attach errors to specific fields:

# Example from django/contrib/auth/forms.py
try:
password_validation.validate_password(password, user)
except ValidationError as error:
self.add_error(password_field_name, error)

Displaying Password Requirements

To help users choose a valid password before they submit a form, you can retrieve the help text from all configured validators using password_validators_help_texts().

from django.contrib.auth.password_validation import password_validators_help_texts

# Returns a list of strings like ["Your password must contain at least 8 characters.", ...]
help_texts = password_validators_help_texts()

In a Django template, you can use the password_validators_help_text_html utility to render these requirements as an HTML list:

<!-- In your template -->
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<div class="password-requirements">
{{ password_validators_help_text_html }}
</div>
<button type="submit">Change Password</button>
</form>

Troubleshooting

Similarity Check and Anonymous Users

The UserAttributeSimilarityValidator requires a user object to perform its checks. If you pass user=None to validate_password(), this validator will silently pass because it has no attributes to compare against.

# This will NOT check for similarity to username/email
validate_password("mypassword", user=None)

Validator Configuration Errors

If you provide an invalid path in AUTH_PASSWORD_VALIDATORS, Django raises an ImproperlyConfigured error when the validators are first loaded. Ensure the NAME key contains the full Python import path to the validator class.

Similarity Threshold

If UserAttributeSimilarityValidator is too strict or too lenient, adjust the max_similarity option. Note that setting max_similarity below 0.1 will raise a ValueError during initialization.

# settings.py
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
'OPTIONS': {
'max_similarity': 0.5, # More lenient than default 0.7
}
}