Flagrant Badassery

A JavaScript and regular expression centric blog

JavaScript Password Validation

Since I've seen tons of password validation help requests on regexadvice.com (where I hang out from time to time), I've written up a more general-purpose JavaScript password validation function. It's reasonably straightforward, and covers the validation requirements I've most frequently encountered. Plus, if it doesn't handle your exact needs, its functionality can be augmented by passing it custom functions and regular expressions.

Here are the validation types supported out of the box. All are optional, which means that all passwords are allowed by default.

  • Minimum and maximum length.
  • Minimum n lowercase characters (a–z).
  • Minimum n uppercase characters (A–Z).
  • Minimum n combined a–z and A–Z characters.
  • Minimum n numeric characters (0–9).
  • Minimum n special characters (characters other than a–z, A–Z, and 0–9).
  • Ban particular words (tested case-insensitively).
  • Ban n-length character sequences (e.g. "abc", "XYZ", or "789", with a sequence length of 3; does not apply to special characters).
  • Ban n-length qwerty character sequences (e.g. "qwerty" or "asdf", with a sequence length of 4; does not apply to special characters).
  • Ban sequential, identical characters (e.g. "aa" or "!!").
  • Use custom regular expressions (tested using RegExp.prototype.test) and functions (the password is provided as the first argument, and a Boolean value is expected in return).

Here's an example of how it can be used:

var password = "password";
var passed = validatePassword(password, {
	length:   [8, Infinity],
	lower:    1,
	upper:    1,
	numeric:  1,
	special:  1,
	badWords: ["password", "steven", "levithan"],
	badSequenceLength: 4
});
// passed: false

The above requires that password is at least eight characters long; has at least one lowercase, uppercase, numeric, and special character; doesn't include the words "password", "steven", or "levithan"; and doesn't include an alphanumeric sequence four or more characters in length (e.g. "1234").

Here's the code (there are no external library dependencies):

/*
	Password Validator 0.1
	(c) 2007 Steven Levithan <stevenlevithan.com>
	MIT License
*/

function validatePassword (pw, options) {
	// default options (allows any password)
	var o = {
		lower:    0,
		upper:    0,
		alpha:    0, /* lower + upper */
		numeric:  0,
		special:  0,
		length:   [0, Infinity],
		custom:   [ /* regexes and/or functions */ ],
		badWords: [],
		badSequenceLength: 0,
		noQwertySequences: false,
		noSequential:      false
	};

	for (var property in options)
		o[property] = options[property];

	var	re = {
			lower:   /[a-z]/g,
			upper:   /[A-Z]/g,
			alpha:   /[A-Z]/gi,
			numeric: /[0-9]/g,
			special: /[\W_]/g
		},
		rule, i;

	// enforce min/max length
	if (pw.length < o.length[0] || pw.length > o.length[1])
		return false;

	// enforce lower/upper/alpha/numeric/special rules
	for (rule in re) {
		if ((pw.match(re[rule]) || []).length < o[rule])
			return false;
	}

	// enforce word ban (case insensitive)
	for (i = 0; i < o.badWords.length; i++) {
		if (pw.toLowerCase().indexOf(o.badWords[i].toLowerCase()) > -1)
			return false;
	}

	// enforce the no sequential, identical characters rule
	if (o.noSequential && /([\S\s])\1/.test(pw))
		return false;

	// enforce alphanumeric/qwerty sequence ban rules
	if (o.badSequenceLength) {
		var	lower   = "abcdefghijklmnopqrstuvwxyz",
			upper   = lower.toUpperCase(),
			numbers = "0123456789",
			qwerty  = "qwertyuiopasdfghjklzxcvbnm",
			start   = o.badSequenceLength - 1,
			seq     = "_" + pw.slice(0, start);
		for (i = start; i < pw.length; i++) {
			seq = seq.slice(1) + pw.charAt(i);
			if (
				lower.indexOf(seq)   > -1 ||
				upper.indexOf(seq)   > -1 ||
				numbers.indexOf(seq) > -1 ||
				(o.noQwertySequences && qwerty.indexOf(seq) > -1)
			) {
				return false;
			}
		}
	}

	// enforce custom regex/function rules
	for (i = 0; i < o.custom.length; i++) {
		rule = o.custom[i];
		if (rule instanceof RegExp) {
			if (!rule.test(pw))
				return false;
		} else if (rule instanceof Function) {
			if (!rule(pw))
				return false;
		}
	}

	// great success!
	return true;
}

You can download it here.

Lemme know if you have any feature requests or other suggestions about how to improve it, or if you need help writing custom rules for it.

There Are 9 Responses So Far. »

  1. Thanks for the comment. I’m looking forward to posting more substantive info.

  2. That’s great to hear, Dean!

    For the record, based on Dean’s email address I assume he’s Dean Hachamovitch, General Manager of the IE team, and that his response was regarding a comment where I poked fun at the apparent lack of humor of some other commenters on the IE blog and mentioned that I was looking forward to seeing him keep his promise regarding more IE8 info in the near future.

  3. Hi. I use Passpack to store my password online (http://www.passpack.com). During registration, for example, they checks your password measuring the quality in bit. Your password must be at least 64-bit quality. Maybe, you could have a look at their approach. It is very interesting.
    Argo

  4. Hmm… their password rating system is quite pretty. However, it’s not equivalent to this for several reasons. For one, it’s designed exclusively for their site and they make it very clear that the code is not open source. Secondly, it gives you a sliding scale of “password quality,” rather than a pass/fail system. That’s good if you’re just trying to assist users with selecting a good password, but not as good if you’re trying to meet pre-defined business requirements about password validation. Third, their system relies on password length and basic character types, but doesn’t do any of the more fancy kinds of validation you can see here.

    I’d considered implementing a quality score system, but that would significantly complicate things considering that the goal of this script is to let people who use it decide how they measure password strength, in order for it to be usable in more cases.

  5. Well, of course this is only one half of the whole thing: at serverside you´ll need to do the same thing in your preferred serverside language. That´s why I love ASP.NET Ajax - just define the regex you wanna use and the framework creates the js for you, while you´re focussing on writing the server-side part of it. Frameworks rock!

  6. How would the sequential identical check be modified to allow 2, but not 3 or more characters?

  7. @JKatelman, here’s one way:

    validatePassword(pw, {custom:[/^(?!.*(.)\1\1)/]});

  8. Thanks for the response. I should have been a little more clear in what I was asking. The condition /([\S\s])\1/.test(pw) is a boolean for not allowing two characters. Is there a similar way to have a single condition that acts like a boolean for three characters?

  9. Yes. /([\S\s])\1\1/. But why would you fork the code for something like this when it makes it easy to provide custom validation rules? As an alternative to the standalone regex in my last comment, you could pass in the custom function function(pw){return !/([\S\s])\1\1/.test(pw);}.

Post a Response

If you are about to post code, please escape your HTML entities (&amp;, &gt;, &lt;).