DEV Community

Cover image for Day 2 of my 21-day API challenge, built a Password Strength & Security Scorer API
Ruan Muller
Ruan Muller

Posted on

Day 2 of my 21-day API challenge, built a Password Strength & Security Scorer API

Day 2 of my 21-day API challenge is done.

Yesterday I built an Invoice & Receipt Parser API. Today I built a Password Strength & Security Scorer API — a complete password security toolkit that any developer can drop into their signup flow in minutes.

If you missed Day 1, catch up here: https://dev.to/ruanmuller04


The Problem

Every app with a login form needs password validation. Most developers end up writing the same basic checks:

// The lazy version every dev writes at 2am
if (password.length < 8) return "too short";
if (!/[A-Z]/.test(password)) return "needs uppercase";
Enter fullscreen mode Exit fullscreen mode

It works. But it misses so much — common breached passwords, keyboard patterns, crack time estimates, entropy calculations. Building all of that properly takes days.

So I built an API that does it properly in one call.


What I Built

The Password Strength & Security Scorer API — send it a password, get back a full security report.

Input:

{
  "password": "password123"
}
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "success": true,
  "data": {
    "score": 0,
    "grade": "F",
    "strength": "very weak",
    "entropy_bits": 58.5,
    "crack_time": {
      "display": "5 months",
      "online_attack": "58 years",
      "offline_attack": "5 months"
    },
    "patterns": {
      "is_common_password": true,
      "has_sequential_nums": true,
      "ends_with_number": true
    },
    "feedback": [
      "This is one of the most common passwords",
      "Contains sequential numbers (e.g. 123)",
      "Ends with a number — very predictable"
    ],
    "suggestions": [
      "Choose a completely different password",
      "Add uppercase letters (A-Z)",
      "Add symbols (!@#$%^&*)"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

And for a strong password:

{
  "password": "K#9mP$vL2@nQ8xR!"
}
Enter fullscreen mode Exit fullscreen mode
{
  "score": 75,
  "grade": "B",
  "strength": "strong",
  "crack_time": { "display": "2 million years" }
}
Enter fullscreen mode Exit fullscreen mode

The 6 Endpoints

Method Endpoint Description
GET /health Health check
POST /analyze Full password analysis
POST /analyze/batch Analyze up to 20 passwords at once
POST /check/breach Check against 500+ breached passwords
POST /generate Generate strong passwords
POST /compare Compare two passwords side by side

The /generate endpoint is my favourite — it returns strong passwords with their scores so you can show users exactly how secure the suggested password is.


How the Scoring Works

The score (0-100) is calculated from four components:

1. Length (0-30 points)

6 chars  →  5 pts
8 chars  → 10 pts
12 chars → 20 pts
16 chars → 25 pts
20+ chars → 30 pts
Enter fullscreen mode Exit fullscreen mode

2. Character sets (0-28 points)
Each charset adds 7 points:

  • Lowercase letters
  • Uppercase letters
  • Numbers
  • Symbols

3. Unique character ratio (0-15 points)
Rewards passwords where characters don't repeat.

4. Entropy (0-15 points)
Calculated as: length × log2(pool_size)

Penalties applied for:

  • Common passwords: -40 points
  • Keyboard walks (qwerty, asdfgh): -20 points
  • Repeated characters (aaa): -10 points
  • Sequential numbers (123): -10 points
  • All numbers or all letters: -15 points

Crack Time Estimation

This was the most interesting part to build. The formula:

function estimateCrackTime(password, charsets) {
  let poolSize = 0;
  if (charsets.has_lowercase) poolSize += 26;
  if (charsets.has_uppercase) poolSize += 26;
  if (charsets.has_numbers)   poolSize += 10;
  if (charsets.has_symbols)   poolSize += 32;

  const combinations = Math.pow(poolSize, password.length);

  // Modern GPU: 10 billion guesses/second
  const seconds = combinations / 1e10;

  return formatTime(seconds);
}
Enter fullscreen mode Exit fullscreen mode

The difference between online and offline attacks matters:

  • Online attack — 10 million/sec (limited by server rate limiting)
  • Offline attack — 10 billion/sec (attacker has the hash file)

password123 cracks in 5 months offline but 58 years online. That's why rate limiting matters even if your hashing is weak.


Breach Detection

The API checks against the 500 most common breached passwords — the ones that appear in every data breach dump.

const COMMON_PASSWORDS = new Set([
  "password", "123456", "qwerty", "abc123", "monkey",
  "letmein", "trustno1", "dragon", "baseball", "iloveyou",
  // ... 490 more
]);

function checkBreach(password) {
  const is_compromised = COMMON_PASSWORDS.has(password.toLowerCase());
  return {
    is_compromised,
    risk_level: is_compromised ? "critical" : "low",
  };
}
Enter fullscreen mode Exit fullscreen mode

Tech Stack

  • Runtime: Node.js + Express
  • Hosting: Railway (free tier)
  • Marketplace: RapidAPI
  • Dependencies: express, cors, helmet, morgan, express-rate-limit

Zero paid APIs. Zero AI. The whole thing costs less than $5/month to run.


Score Guide

Score Grade Strength
80-100 A Very Strong
60-79 B Strong
40-59 C Moderate
20-39 D Weak
0-19 F Very Weak

Recommended minimum for most apps: Grade B (60+)
Recommended for financial apps: Grade A (80+)


Try It

Live on RapidAPI — search Password Strength Security Scorer or find me at rapidapi.com/user/ruanmul04.

Free tier: 10 requests/month. No credit card required.


What's Next

Day 3 tomorrow — VAT Number Validator API.

Every e-commerce platform selling to Europe needs VAT validation. There are almost no good free options on RapidAPI. That's the gap I'm filling tomorrow.

Follow me here on dev.to to catch every day of the challenge. 🇿🇦


21 APIs in 21 days. Built in South Africa. Sold globally.

Top comments (0)