Most password strength meters on signup forms are black boxes — a colored bar shifts from red to green and you have no idea what's actually being measured. So I built a small, transparent version: a scoring function you can read top to bottom and understand exactly why a password got the rating it did.
The goal isn't cryptographic rigor — it's a clear, tweakable scorecard you can drop into a form for live feedback.
1. The scoring rules
Four checks, each worth points: length, uppercase presence, digit presence, and symbol presence. Each failed check also generates a specific tip.
import re
def check_strength(password):
score = 0
tips = []
if len(password) >= 12:
score += 2
elif len(password) >= 8:
score += 1
else:
tips.append("Use at least 8 characters")
if re.search(r"[A-Z]", password):
score += 1
else:
tips.append("Add an uppercase letter")
if re.search(r"[0-9]", password):
score += 1
else:
tips.append("Add a number")
if re.search(r"[^A-Za-z0-9]", password):
score += 1
else:
tips.append("Add a symbol")
return score, tips
Length gets weighted more heavily than the other checks (2 points for 12+ characters vs. 1 point for each other rule), since length is generally the strongest predictor of real-world password strength.
2. Turning the score into a label
A raw number isn't user-friendly, so the score maps to one of six labels.
def strength_label(score):
levels = ["Very Weak", "Weak", "Okay", "Good", "Strong", "Very Strong"]
return levels[min(score, len(levels) - 1)]
The min(score, len(levels) - 1) guards against an out-of-range index if the scoring rules ever get extended and start producing higher totals.
3. Putting it together
def evaluate_password(password):
score, tips = check_strength(password)
label = strength_label(score)
return {"score": score, "label": label, "tips": tips}
4. The full script, start to end
import re
def check_strength(password):
score = 0
tips = []
if len(password) >= 12:
score += 2
elif len(password) >= 8:
score += 1
else:
tips.append("Use at least 8 characters")
if re.search(r"[A-Z]", password):
score += 1
else:
tips.append("Add an uppercase letter")
if re.search(r"[0-9]", password):
score += 1
else:
tips.append("Add a number")
if re.search(r"[^A-Za-z0-9]", password):
score += 1
else:
tips.append("Add a symbol")
return score, tips
def strength_label(score):
levels = ["Very Weak", "Weak", "Okay", "Good", "Strong", "Very Strong"]
return levels[min(score, len(levels) - 1)]
def evaluate_password(password):
score, tips = check_strength(password)
label = strength_label(score)
return {"score": score, "label": label, "tips": tips}
if __name__ == "__main__":
for pw in ["abc", "abcdefgh", "Coffee123", "Coffee123!"]:
result = evaluate_password(pw)
print(pw, "->", result)
5. Trying it out
| Password | Label | Tips |
|---|---|---|
abc |
Very Weak | Use at least 8 characters, add uppercase, add a number, add a symbol |
abcdefgh |
Weak | Add uppercase, add a number, add a symbol |
Coffee123 |
Good | Add a symbol |
Coffee123! |
Very Strong | — |
Wrap-up
This isn't a replacement for a real password-strength library like zxcvbn, which models actual attacker behavior (common patterns, dictionary words, keyboard walks). But for a lightweight, dependency-free check with human-readable feedback, a rule-based scorecard like this does the job — and it's easy to extend with your own rules if you want to penalize common passwords or repeated characters.
Note: strength scoring like this estimates resistance to guessing, not resistance to leaked-password reuse — always pair it with breach-check tools like Have I Been Pwned's API for real-world security.
Top comments (0)