zxcvbn-ts

A TypeScript rewrite of Dropbox's zxcvbn password strength estimator, with pluggable dictionaries and async matcher support.

Library
npm
v4.2.0
1,236 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
66 /100 Good
Development Activity 72
Maintenance 32
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
81 /100 Excellent
Architecture 82
Code Quality 88
Innovation 78
Learning Curve 75

@zxcvbn-ts/core is a complete TypeScript rewrite of Dropbox’s original zxcvbn password strength estimator. Instead of relying on brittle composition rules (“must contain a number and a symbol”), it estimates how many guesses an attacker would realistically need by matching the password against dictionaries of common passwords, names, and Wikipedia words, plus pattern matchers for dates, keyboard walks, repeats, sequences, and l33t-speak substitutions.

The library ships with zero bundled dictionaries or language data by default — consumers install a @zxcvbn-ts/language-* package (common, en, and dozens of locales) and pass the dictionaries, keyboard adjacency graphs, and translations into the ZxcvbnFactory constructor. This keeps the core bundle small and makes internationalization an explicit opt-in rather than dead weight for apps that only need one locale. A synchronous check() and a checkAsync() (for API-backed matchers like Have I Been Pwned) cover both usage styles, and a custom-matcher API lets consumers plug in their own pattern detectors alongside the built-in ones.

What You Get

  • A ZxcvbnFactory class that scores any password 0-4 and returns crack-time estimates across four attack scenarios (offline fast/slow hashing, online throttled/unthrottled)
  • Ten built-in matchers (dictionary, dictionary-l33t, dictionary-reverse, date, regex, repeat, sequence, spatial, separator, word-sequence) run against every password in one pass
  • Pluggable dictionary and language packages (@zxcvbn-ts/language-common, -en, and locale packs) so the core bundle stays free of data you don’t need
  • Human-readable feedback (warning + suggestions) generated per match, with a full translation-key system for localizing that feedback
  • A custom-matcher API and checkAsync() for wiring in your own pattern detectors, including asynchronous ones like a Have I Been Pwned lookup
  • Full TypeScript types for every input and output shape, published alongside CJS/ESM builds

Common Use Cases

  • Live password-strength meters on signup and password-reset forms
  • Blocking weak passwords server-side as an alternative to rigid composition-rule policies
  • Feeding a numeric strength score into a broader account-security or risk-scoring pipeline
  • Combining the sync scorer with an async Have I Been Pwned matcher to flag both weak and previously-breached passwords in one check

Under The Hood

Architecture

The library is organized around a ZxcvbnFactory (src/index.ts) that composes four collaborators built from a shared Options instance: Matching (src/Matching.ts), Scoring (src/scoring/index.ts), Feedback, and TimeEstimates. Matching runs all ten registered matchers (dictionary variants, date, regex, repeat, sequence, spatial, separator, word-sequence, plus any custom ones from options.matchers) against the password in one match() call, collecting synchronous results directly and awaiting any matcher that returns a Promise via handlePromises. Scoring.mostGuessableMatchSequence then picks the minimal-guess partition of the password from the combined match set, and TimeEstimates converts the resulting guess count into crack-time estimates across four attack models. Swapping the core scoring algorithm would only require changes inside Scoring, since matchers only need to conform to the MatcherBaseClass interface.

Tech Stack

Written in strict TypeScript, built with Rollup (@rollup/plugin-typescript, @rollup/plugin-terser) into dual CJS/ESM output via a shared scripts/rollup.config.mjs, and managed as a Lerna + Yarn-workspaces + Turbo monorepo (packages/libraries/*, packages/languages/*). The only runtime dependency of the core package is fastest-levenshtein, used for optional fuzzy dictionary matching. Documentation is built with VuePress and published to GitHub Pages.

Code Quality

The main package has 43 spec files under test/ (Jest with @swc/jest transform) covering matchers, scoring, options validation, custom matchers, async matchers, and translations, including full input/output snapshot-style assertions on ZxcvbnFactory.check(). ESLint runs typescript-eslint’s strictTypeChecked/stylisticTypeChecked rule sets plus eslint-plugin-compat, eslint-plugin-jest, and eslint-plugin-sort-class-members, formatted with Prettier, and CI (build.yml, lint.yml, test.yml, testTypes.yml) runs lint, Jest with coverage, a full build, and @arethetypeswrong/cli type-export checks on every push.

What Makes It Unique

Rather than brute-forcing l33t-speak substitutions, Options precomputes a TrieNode from the l33t substitution table (l33tTableToTrieNode) so l33t variants of dictionary words are matched via trie traversal instead of combinatorial substitution, keeping match time roughly linear in password length. The runtime-validated options system (runtimeChecks.ts) type-checks every custom dictionary, graph, matcher, and translation object at construction time, which is unusually defensive for a library whose entire configuration surface is user-supplied.

Used by 14 apps in this directory

TypeScript
80%
AGPL 3.0

VoidAuth

Authentication · Security

2,889

Self-hosted SSO with OIDC, LDAP, passkeys, and proxy auth for your entire self-hosted stack

View details
83
Repo Health
77
Technical
72
Dependency
Built with
TypeScript 80%
HTML 14%
Updated 6 days ago
TypeScript
80%
AGPL 3.0

VoidAuth

Authentication · Security

2,889

Self-hosted SSO with OIDC, LDAP, passkeys, and proxy auth for your entire self-hosted stack

View details
83
Repo Health
77
Technical
72
Dependency
Built with
TypeScript 80%
HTML 14%
Updated 6 days ago
Python
57%
Apache 2.0

Zulip

Team Chat

26,102

Topic-based team chat that brings the structure of email threads to real-time messaging, so distributed teams never lose context across hundreds of concurrent conversations.

View details
96
Repo Health
86
Technical
60
Dependency
Built with
Python 57%
TypeScript 19%
JavaScript 11%
Updated 6 days ago
Python
57%
Apache 2.0

Zulip

Team Chat

26,102

Topic-based team chat that brings the structure of email threads to real-time messaging, so distributed teams never lose context across hundreds of concurrent conversations.

View details
96
Repo Health
86
Technical
60
Dependency
Built with
Python 57%
TypeScript 19%
JavaScript 11%
Updated 6 days ago
Python
57%
Apache 2.0

Zulip

Team Chat

26,102

Topic-based team chat that brings the structure of email threads to real-time messaging, so distributed teams never lose context across hundreds of concurrent conversations.

View details
96
Repo Health
86
Technical
60
Dependency
Built with
Python 57%
TypeScript 19%
JavaScript 11%
Updated 6 days ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers