BreachCheck API

Check if passwords have been exposed in data breaches using k-anonymity. Our API ensures your users' actual passwords never leave their browser.

K-Anonymity Protected
High Performance
Global Base URL
https://api.pwnedpasswords.com/range/{first5hash}
Authentication: No authentication required
GET

/range/{prefix}

Retrieves a list of SHA-1 hash suffixes that match the first 5 characters of a provided SHA-1 hash.

Parameters

ParameterTypeRequiredDescription
prefixstringYesThe first 5 characters of SHA-1 password hash.

Example Request

curl https://api.pwnedpasswords.com/range/21BD1

Example Response

00111C0997A6C30331282645620C781E8C9:1
00112A0997A6C30331282645620C781E8C9:4
00114C0997A6C30331282645620C781E8C9:12
001150D328C67B665F292B289659CD0F549:1

Security Standards

  • Client-side Hashing

    Plaintext passwords never travel across the network.

  • Mandatory HTTPS

    All traffic is encrypted via TLS 1.3 to prevent sniffing.

  • Zero Data Retention

    Queries are logged anonymously for rate-limiting only.

How to use

01

Hash

Compute the SHA-1 hash of the password locally on the user's device.

02

Prefix

Extract the first 5 characters (e.g., "21BD1") from the hash.

03

Request

Send only the prefix to the API to receive all matching suffixes.

04

Compare

Locally check if your full hash suffix exists in the API response.

async function checkPassword(password: string) {
  // 1. Compute SHA-1 hash locally
  const msgBuffer = new TextEncoder().encode(password);
  const hashBuffer = await crypto.subtle.digest('SHA-1', msgBuffer);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  const hashHex = hashArray
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("").toUpperCase();

  const prefix = hashHex.slice(0, 5);
  const suffix = hashHex.slice(5);

  // 2. Call API with only prefix
  const response = await fetch(`https://api.pwnedpasswords.com/range/${prefix}`);
  const data = await response.text();

  // 3. Compare locally
  const match = data.split("\n")
    .find((line) => line.startsWith(suffix));
  return match ? parseInt(match.split(":")[1]) : 0;
}

Interactive Sandbox

Test the k-anonymity logic in real-time.

00111C0997A6C30331282645620C781E8C9:1 00112A0997A6C30331282645620C781E8C9:4 00114C0997A6C30331282645620C781E8C9:12 001150D328C67B665F292B289659CD0F549:1
Status: 200 OKLatency: 42ms