Integrate in three steps.
The whole integration: hash the password on your server with the knownPass salt, send the first six characters of the hash, compare the returned hashes locally. The raw password and its full hash never leave your infrastructure. One GET request, one JSON response, about 100 ms.
1. Hash locally
Compute the SHA-1 of the fixed salt string followed by the password, as lowercase hex. The first six characters are the prefix you send. The remaining 34 are the suffix you keep.
// any runtime with SHA-1 const hash = sha1("Salted for knownpass.com: " + password).toLowerCase(); const prefix = hash.slice(0, 6); // sent const suffix = hash.slice(6); // kept // "password123" // hash = e4ed298fced32b284fb61840470dd5f9e030b568 // prefix = e4ed29 (sent) // suffix = 8fced32b284fb61840470dd5f9e030b568 (kept, 34 chars)
SHA-1 is a lookup key here, not a password-storage hash. The salt is public and fixed on purpose: it keeps knownPass prefixes from being replayed against other services. Details in the threat model.
2. Send the prefix
GET https://api.knownpass.com/v1/range/{prefix} x-api-key: kpp_…
| Part | Value |
|---|---|
{prefix} | Exactly 6 lowercase hex characters. Anything else returns 422. |
x-api-key | Your API key. Get one from the console; no card. Missing or invalid returns 401. |
$ curl -H "x-api-key: $KP_API_KEY" https://api.knownpass.com/v1/range/e4ed29
3. Compare locally
The response is JSON. prefix echoes what you sent; results maps every known hash in that bucket to the categories it was found in. Keys are full 40-character lowercase hashes, about 1,200 of them for a typical prefix.
{
"prefix": "5baa61",
"results": {
"5baa6100376b63d48b4c8f80a29d72dd7c1da223": ["Brute-force space"],
"5baa6100eab64a319ee7968afca44f70c579e13d": ["Website leaks", "Password lists"],
…
}
}
If the hash you computed in step 1 is a key in results, the password is known: block it at signup and password change, require a change at login. If it isn’t, proceed. The response carries no counts and no plaintexts.
const known = Object.hasOwn(body.results, hash); // hash: the 40-char value from step 1
Categories you may see: Website leaks, Malware leaks, Password lists, Wordlists, Common, Masks & patterns, Brute-force space, Tailored. Treat any match as a block; the categories are for your logs and your users’ error message.
Response codes
| Code | Meaning | What to do |
|---|---|---|
200 | JSON {prefix, results} for the prefix. An empty results object is valid: nothing known in that bucket. | Compare locally. |
422 | Prefix fails validation: not exactly 6 lowercase hex characters. Body is {"detail": [...]}. | Fix the client: length and hex case. |
401 | Missing or invalid x-api-key. | Check the key. Rotate it in the console if it leaked. |
429 | Quota exceeded. Retry-After gives the wait in seconds. | Fail open, back off, consider Team. |
5xx | Our fault. | Fail open. Check the status page. |
Rate limits
- Free and trial keys: 100 requests a day per key. Enough to integrate and test; not enough for production login traffic. Bulk download is not counted against it.
- Team: fair-use quota sized for normal signup, login and reset traffic. Over quota returns
429withRetry-After. - Demo key: the key embedded in the landing-page demo is public and shared. It is throttled and may be rotated without notice. Don’t build on it.
Existing keys get 90 days’ notice before any limit change affects them. Pricing.
Fail open
knownPass is a check, not a dependency. If the request fails, times out, or returns 429 or 5xx: let the flow continue, log that the check was skipped, and re-check at the next login or password change. Suggested client timeout: 800 ms. There is no uptime SLA today; the status page is updated by hand.
Where to put the check
- Signup and password change: block on match and ask for a different password. Tell the user why: “this password appears in known breaches or common lists.”
- Login: check the password the user just typed. On match, let them in and require a change before anything else; it leaked after they set it.
- Reset: same as signup.
The reference is NIST SP 800-63B, section 5.1.1.2: screen against known-compromised and context-specific values; once screening is in place, drop composition rules and periodic rotation.
Machine-readable
- OpenAPI 3.1: knownpass.com/openapi.json live
- llms.txt: knownpass.com/llms.txt live, written for coding assistants. Paste the URL into Claude Code, Cursor or Copilot and ask for the integration; the generated client hashes locally.
- Bulk download:
GET /v1/bulk/{dataset}/manifestlists the published files;GET /v1/bulk/{dataset}/files/{filename}serves them with Range and resume. Included in every tier, Free too: self-hosting needs it. live - Reference client (MIT): a single self-contained JavaScript component. repository link coming
Identity providers
Today: plain REST from any stack, as above. Planned: Keycloak, Zitadel, Ory, Authentik, Nextcloud and Supabase Auth. Design partners decide the order. Integrations · Become a design partner.