# Client-side Password Rule Validation

Learn how to configure FusionAuth to check passwords client-side.

> For the index of this section of the site, see [llms.txt](https://fusionauth.io/docs/llms.txt)

FusionAuth checks password rules in server-side validation, but you can also check them in your client. This page shows one method of doing so in JavaScript.

## Client-side Password Validation Example

FusionAuth provides password rules, configurable at the [tenant level](https://fusionauth.io/docs/get-started/core-concepts/types/tenants.md). These include checks on a password value such as:

*   a password must have one special character
*   a password length must be at least 12 characters, in lowercase, uppercase, or a combination including special characters
*   a password must contain a numeric character

The [latest guidance from NIST recommends avoiding such rules](https://fusionauth.io/articles/security/breached-password-detection.md#what-does-nist-have-to-say-about-breached-password-detection) but if you have internal or external policies requiring password complexity rules, FusionAuth supports it.

These password rules are enforced in the hosted HTML login pages, but only after the user has submitted the form. They are also available as freemarker variables on the [registration page](https://fusionauth.io/docs/theme/advanced-themes/template-variables.md#oauth-register) and the [change password page](https://fusionauth.io/docs/theme/advanced-themes/template-variables.md#oauth-change-password-form).

This example shows how to use the `passwordValidationRules` freemarker variables to offer user feedback client-side using JavaScript, in the hosted login pages. It will also disable submission of the form if the rules are not met.

Save the JavaScript class below as `FusionAuthPasswordChecker.js` and make it available at a public URL. In the registration and change password theme templates, load the file and initialize it with the FreeMarker variables:

```html
<script src="https://yourcdn.example.com/path/to/FusionAuthPasswordChecker.js"></script>
<script>
const minLength = ${passwordValidationRules.minLength};
const maxLength = ${passwordValidationRules.maxLength};
const requireMixedCase = ${passwordValidationRules.requireMixedCase?c};
const requireNonAlpha = ${passwordValidationRules.requireNonAlpha?c};
const requireNumber = ${passwordValidationRules.requireNumber?c};

document.addEventListener('DOMContentLoaded', () => new FusionAuthPasswordChecker(minLength, maxLength, requireMixedCase, requireNonAlpha, requireNumber));
</script>
```

This JavaScript expects the names and DOM structure of the pages to be the same as the default theme structure. If you've modified your theme, this code will be a starting point, but is not guaranteed to work.

You'll also need to create CSS classes `validation` and `ok` to visually inform your users about the status of their password.

Password rules are also available via an [unauthenticated API call](https://fusionauth.io/docs/apis/tenants/retrieve-the-password-validation-rules.md) if you'd prefer to build your own validation logic without using JavaScript. This might be useful for a mobile application, for example.

## JavaScript Code

Save this code as `FusionAuthPasswordChecker.js`:

```javascript
class FusionAuthPasswordChecker {
  #minLength;
  #maxLength;
  #passwordField;
  #feedbackContainer;
  #requireMixedCase;
  #requireNonAlpha;
  #requireNumber;
  #submitButton;
  #timer;

  constructor(minLength, maxLength, requireMixedCase, requireNonAlpha, requireNumber) {
    this.#minLength = minLength;
    this.#maxLength = maxLength;

    this.#requireMixedCase = requireMixedCase;
    this.#requireNonAlpha = requireNonAlpha;
    this.#requireNumber = requireNumber;

    this.#passwordField = document.querySelector('input[type="password"]');
    const form = this.#passwordField?.closest('form');
    this.#submitButton = [...(form?.querySelectorAll('button, input[type="submit"]') ?? [])]
      .find((button) => button.type === 'submit');
    this.#feedbackContainer = this.#passwordField?.closest('.form-row') ?? this.#passwordField?.parentElement?.parentElement;
    this.#timer = null;

    if (this.#passwordField && this.#submitButton && this.#feedbackContainer) {
      this.#passwordField.addEventListener('input', () => this.#score());
      this.#setSubmitEnabled(false);
      this.#score();
    }
  }

  #setSubmitEnabled(enabled) {
    this.#submitButton.disabled = !enabled;
    this.#submitButton.classList.toggle('disabled', !enabled);
  }

  #check(password, check, errorTextSupplier) {
    if (check(password)) {
      return;
    }

    this.#invalid(errorTextSupplier());
  }

  #score() {
    if (this.#timer !== null) {
      clearTimeout(this.#timer);
    }

    this.#timer = setTimeout(() => {
      this.#feedbackContainer.querySelector('.fa-password-rule-error')?.remove();

      const password = this.#passwordField.value;
      if (password.length === 0) {
        this.#passwordField.classList.remove('ok', 'validation');
        this.#setSubmitEnabled(false);
        return;
      }

      this.#check(password, (value) => value.length >= this.#minLength, () => 'too short');
      this.#check(password, (value) => value.length <= this.#maxLength, () => 'too long');

      if (this.#requireNumber) {
        this.#check(password, (value) => /\d/.test(value), () => 'must contain a number');
      }

      if (this.#requireMixedCase) {
        this.#check(password, (value) => /[a-z]/.test(value) && /[A-Z]/.test(value), () => 'must contain mixed case');
      }

      if (this.#requireNonAlpha) {
        this.#check(password, (value) => /\W/.test(value), () => 'must contain a special character');
      }

      if (this.#feedbackContainer.querySelector('.fa-password-rule-error') === null) {
        // Add classes, or style to provide visual feedback
        this.#passwordField.classList.add('ok');
        this.#passwordField.classList.remove('validation');

        this.#setSubmitEnabled(true);
      }

    }, 500);
  }

  #invalid(errorText) {
    // Add classes, or style to provide visual feedback
    this.#passwordField.classList.add('validation');
    this.#passwordField.classList.remove('ok');

    let errorSpan = this.#feedbackContainer.querySelector('.fa-password-rule-error');
    if (errorSpan === null) {
      errorSpan = document.createElement("span");
      errorSpan.classList.add('error', 'fa-password-rule-error');
      this.#feedbackContainer.appendChild(errorSpan);
    }

    if (errorSpan.textContent !== '') {
      errorSpan.textContent += ', ';
    }

    errorSpan.textContent += errorText;
    this.#setSubmitEnabled(false);
  }
}
```

Related

[APIs Retrieve the Password Validation Rules API API documentation for the FusionAuth Retrieve the Password Validation Rules API. password validationpassword rules](https://fusionauth.io/docs/apis/tenants/retrieve-the-password-validation-rules.md)

[APIs Form Field API Learn about the APIs for creating, retrieving, updating and deleting form fields. user registration](https://fusionauth.io/docs/apis/custom-forms/form-fields.md)

[APIs Form API Learn about the APIs for creating, retrieving, updating and deleting forms. user registration](https://fusionauth.io/docs/apis/custom-forms/forms.md)

[APIs Create a User and Registration (combined) API API documentation for the FusionAuth Create a User and Registration (combined) API. user registration](https://fusionauth.io/docs/apis/registrations/create-a-user-and-registration-combined.md)
---

## Other pages in Advanced Themes

> For the full index of this section, see [Theme](https://fusionauth.io/docs/llms-theme.txt).

- [Theme Examples](https://fusionauth.io/docs/theme/advanced-themes/examples.md): A list of FusionAuth themes examples.
- [Themes Helper Macros](https://fusionauth.io/docs/theme/advanced-themes/helpers.md): Learn about the Freemarker macros FusionAuth provides to help with theming.
- [Advanced Themes](https://fusionauth.io/docs/theme/advanced-themes.md): Learn how to theme and the FusionAuth login pages (including forgot password, two-factor authentication and others).
- [Add a Theme to a Kickstart](https://fusionauth.io/docs/theme/advanced-themes/kickstart-custom-theme.md): Learn how to use Kickstart to create a FusionAuth Instance with a custom theme.
- [Tailwind CSS](https://fusionauth.io/docs/theme/advanced-themes/tailwind.md): Detailed documentation for integrating Tailwind CSS in FusionAuth.
- [Theme Template Variables](https://fusionauth.io/docs/theme/advanced-themes/template-variables.md): Detailed documentation about the theme template variables.
- [Upgrade an Advanced Theme](https://fusionauth.io/docs/theme/advanced-themes/upgrade-advanced-theme.md): An overview of how to upgrade a custom theme from one version of FusionAuth to another.
- [Advanced Theme Upgrade Notes](https://fusionauth.io/docs/theme/advanced-themes/upgrade.md): Detailed information about required theme changes between versions of FusionAuth.
