Password Strength `meter`
The following is a guest post by Pankaj Parashar. Pankaj is our resident expert on all things and
and this post is more evidence of that. Here, he walks us through implementing a password strength meter using what is likely the semantically best option.
A number of major websites like Dropbox, Gmail and eBay, rely on some kind of an indicator to indicate the strength of the password to the user during registration. The indicator serves as a good reminder for the user as to the level of difficulty to crack the password.
Although this practice is not new, most of the implementation for the password strength indicator I’ve seen so far uses the same old markup of
to represent the indicator. With the introduction of HTML5, we now have the ability to use the
element in our markup, which in my opinion, is semantically more accurate and perfectly suitable for this password strength indicator use-case. Throughout this article, we’ll call it the password strength meter.
Why not use the HTML5
element?
As the name suggests, the HTML5 element is used to indicate the progress of a task or an activity. Representing the strength of the password, isn’t really a task or activity. It’s not something that has progress towards a goal or is ever complete. Hence, it is safe to conclude that the
element is not the right candidate for this use-case.
How to calculate the strength of a password?
We’ll be using the zxcvbn library by Dropbox to calculate the strength of the password. There are quite a few alternative JavaScript libraries that computes the strength of a password, but zxcvbn is perfect for our use case because:
- It provides a simple API that takes a password as the input and returns a score from 0 to 4 as the output to indicate the strength of a password (0 – weakest, 4 – strongest). This works quite well with our
element, that can accept a
value
within a predefinedmin
–max
range. - It estimates a realistic strength of the password, by detecting all the possible overlapping patterns and then matches it against several English dictionaries, common passwords, keyboard patterns and repetitions.
- It is built by Dropbox! The official blog provides much more information on the technical details about the algorithm.
If you are not familiar with the HTML5 element, then CSS-Tricks has just the right article, to get you up and running with the basics. I would strongly recommend reading it before you proceed with this article.
Basic markup
Let’s start with a basic markup: an field that accepts a password, with a paired
.
<label for="password">Enter password</label>
<input type="password" id="password" required>
We’ll add the element below the
along with a text element where we can affirm and explain the current value represented by the meter element. Since, zxcvbn returns a value in range of 0 to 4, the minimum possible value of the meter is
0
whereas the maximum possible value is 4
. If not specified, the default value of the min
attribute is always 0
.
<meter max="4" id="password-strength-meter"></meter>
<p id="password-strength-text"></p>
W3C recommends including a textual representation of the current value inside the meter tag for older browsers. However, we’ll keep it blank for now and discuss the possible fallback techniques later in the article.
Styling the meter
In this section, we will only focus on styling the element. I’ll leave the styling of the rest of the markup as an exercise for you. In order to understand how to style the
element, we need to peek under the hood of the browsers to deconstruct the implementation of the
element.
For example, this is how Blink/Webkit and Gecko based browsers decompose the tag:
The zxcvbn library returns a score from 0 to 4. This means that there are five possible values for our password strength meter. We can target each one of them using the attribute selector, eg., meter[value="0"]
, meter[value="1"]
etc.,
The score represents the strength of the password. The higher the score, the more difficult is the password to crack. We will represent each score with a different color to provide a visual feedback to the user. We can skip styling the value="0"
, as it will not be visible.
Styling the meter bar
meter {
/* Reset the default appearance */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
margin: 0 auto 1em;
width: 100%;
height: 0.5em;
/* Applicable only to Firefox */
background: none;
background-color: rgba(0, 0, 0, 0.1);
}
meter::-webkit-meter-bar {
background: none;
background-color: rgba(0, 0, 0, 0.1);
}
Styling the meter value
/* Webkit based browsers */
meter[value="1"]::-webkit-meter-optimum-value { background: red; }
meter[value="2"]::-webkit-meter-optimum-value { background: yellow; }
meter[value="3"]::-webkit-meter-optimum-value { background: orange; }
meter[value="4"]::-webkit-meter-optimum-value { background: green; }
/* Gecko based browsers */
meter[value="1"]::-moz-meter-bar { background: red; }
meter[value="2"]::-moz-meter-bar { background: yellow; }
meter[value="3"]::-moz-meter-bar { background: orange; }
meter[value="4"]::-moz-meter-bar { background: green; }
Updating the meter
Before we proceed, lets include the zxcvbn library from cdnjs right before the body element using a tag.
<script src="https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.2.0/zxcvbn.js"></script>
zxcvbn adds a single function to the global namespace. It takes one required argument (a password) and returns a resultant object with the following properties:
- guesses – Estimated no. of guesses needed to crack the password
- guesses_log10 – Logarithmic value of guesses to the base 10
- crack_time_seconds – Estimation of the actual crack time, in seconds
- crack_time_display – Crack time in a human readable format, like, “3 hours” etc
- score – Integer in a range 0-4 (this is what we will be using for the meter)
- feedback.warning – Explains what’s wrong with the entered password
- feedback.suggestions – List of suggestions to help choose a less guessable password
- sequence – List of patterns that zxcvbn based the guess calculation on
- calc_time – The time it took the zxcvbn to calculate an answer, in milliseconds
zxcvbn also includes an optional user_inputs
argument which accepts an array of strings that it uses as a blacklist to penalize passwords containing user’s personal information from other fields like name, email etc.
Now every time the password field is changed, we will pass the password to the zxcvbn function and update the meter using the resultant score
. In addition to updating the value
attribute of the meter, we will also update the accompanying text to indicate the strength of the password to the user.
Firstly, we will map the scores to a human readable format,
var strength = {
0: "Worst",
1: "Bad",
2: "Weak",
3: "Good",
4: "Strong"
}
Secondly, attach a listener to the password field that will listen for the changes and then update the meter and the text indicator.
var password = document.getElementById('password');
var meter = document.getElementById('password-strength-meter');
var text = document.getElementById('password-strength-text');
password.addEventListener('input', function() {
var val = password.value;
var result = zxcvbn(val);
// Update the password strength meter
meter.value = result.score;
// Update the text indicator
if (val !== "") {
text.innerHTML = "Strength: " + strength[result.score];
} else {
text.innerHTML = "";
}
});
The demo Pen additionally employs feedback.warnings
and feedback.suggestions
to provide a relevant and useful feedback to the user, to help them choose a less-guessable password.
See the Pen Password strength meter by Pankaj Parashar (@pankajparashar) on CodePen.
If for any reason the demo fails in your browser, you can watch this video.
Fallback
As it stands, our password strength meter works quite well in all the browsers that support the HTML5 element. The good thing is, we do not have to worry about the browsers that don’t support it. Those browsers will simply ignore the
tag and render the text after the meter, which is a decent fallback to indicate the strength of the password to the user.
If you’re determined to provide a consistent user experience across all the browsers, you could simulate the appearance of the meter using a combination of
markup inside the
element. Browsers that do not understand the
tag will simply ignore it and instead render the markup inside. I’ve described this method in detail in the fallback section of my previous article on CSS-Tricks on the same topic.
Are password strength meters good from the UX point of view?
This article doesn’t intend to spark a debate on whether password strength meters are good or not. There are probably, rational and reasonable arguments on both the sides. However, most of the argument stems from the inability of the algorithm to provide a realistic measure of the strength of the password. I think Dropbox has nailed it with the zxcvbn library because it offers a much more realistic estimation of how difficult is the password to crack.
Whether you use it in your design or not, is up to you. But if you decide to take the plunge, then make sure you use the HTML5 element!
Password Strength `meter` is a post from CSS-Tricks