Breached password detection protects your users by making sure they aren’t using passwords that have been seen in [previous breaches](https://haveibeenpwned.com/PwnedWebsites).

An easy way to provide it to your users is:

```js
const {pwnedPassword} = require('hibp');

async function hasPasswordBeenUsedBefore(password) {
    // HIBP asks that you identify yourself through the user agent
    const numTimesUsedBefore = await pwnedPassword(password, {userAgent: "whoami"});
    return numTimesUsedBefore > 0;
}
```

[HIBP (or have i been pwned?)](https://haveibeenpwned.com/) is a service that provides APIs on top of past breaches. In the code snippet, I used the library [`hibp`](https://www.npmjs.com/package/hibp), but there are existing libraries for pretty much every language. The [API](https://haveibeenpwned.com/API/v3#PwnedPasswords) is easy to use if you prefer to not rely on a library here.

Let’s test our function:

```js
async function testPasswords() {
    const passwords = ["password", "p455w0rd!!", "iamsosecure", "48lU!#S032XN2tzbh"]
    for (const password of passwords) {
        const usedBefore = await hasPasswordBeenUsedBefore(password);
        console.log(password, usedBefore);
    }
}

testPasswords()
// password true
// p455w0rd!! true
// iamsosecure false
// 48lU!#S032XN2tzbh false
```

We can see that `password` is a pretty easy thing to catch, whereas `p455w0rd!!` is more subtle and would have passed any “8 characters, at least 1 number and special character” requirements.

Neither `iamsosecure` or `48lU!#S032XN2tzbh` were in any past breaches, which is important to note. This isn’t a guarantee that the password is high quality, just that it hasn’t been seen in a breach before. However, there are currently over 600M easily attackable passwords that you will now disallow in only a few lines of code.

### Technical note: Is the password sent in plaintext?

No, the API is designed to not accept plaintext passwords. Instead, you send the first 5 characters of the SHA-1 hash of the password. The response is a list of SHA-1 hash suffixes (everything after the first 5 characters), that begin with those 5 characters. You can check your hash against this list locally.

Example from [the API docs](https://haveibeenpwned.com/API/v3#PwnedPasswords)

```text
GET https://api.pwnedpasswords.com/range/{first 5 hash chars}

0018A45C4D1DEF81644B54AB7F969B88D65:1
00D4F6E8FA6EECAD2A3AA415EEC418D38EC:2
011053FD0102E94D6AE2F8B83D76FAF94F6:1
012A7CA357541F0AC487871FEEC1891C49C:2
0136E006E24E7D152139815FB0FC6A50B15:2
...
```
