Skip to content
Back to catalog
Have I Been Pwned

Breached password detection with Have I Been Pwned

Flag, reject, or block passwords that appear in known data breaches

Have I Been Pwned is a data breach search service run by security researcher Troy Hunt. Its Pwned Passwords corpus collects passwords exposed in real data breaches, and its range API lets services check a password against it without sending the password.

How does the integration work?

Breached password detection is a password policy in Appwrite Auth that checks your users' passwords against Have I Been Pwned. Appwrite runs the check when a user signs up, signs in with email and password, changes their password, or completes a password recovery, and stores the result on the user as passwordPwned.

The check uses k-anonymity. Appwrite hashes the password with SHA-1 and sends only the first five characters of the hash to the Pwned Passwords API. The API returns every known hash suffix for that prefix, and Appwrite compares them on its own servers, so neither the password nor its full hash leaves Appwrite.

On top of recording the result, you can turn on two enforcement options:

  • Reject breached passwords. A breached password can't be set at sign-up, password change, or password recovery, including through the server-side Users API. The request fails with the password_pwned error.
  • Block sign-in with a breached password. An email and password sign-in with a breached password fails with the user_password_reset_required error until the user resets their password.

If the service can't be reached, Appwrite doesn't treat the password as safe. The request fails with the general_pwned_passwords_unavailable error and can be retried.

How to implement

To implement breached password detection in Appwrite Auth, there are several steps you must complete:

Step 1: Connect your self-hosted instance to Have I Been Pwned

Skip this step on Appwrite Cloud. If you self-host Appwrite, the default value of _APP_PWNED_PASSWORDS_DSN, none://localhost, reports every password as safe. Point it at the public Pwned Passwords range API in the .env file of your Appwrite installation:

Bash
_APP_PWNED_PASSWORDS_DSN=hibp://localhost

Then recreate your Appwrite stack and confirm the variable was applied:

Bash
docker compose up -d
docker compose exec appwrite vars

Step 2: Configure the breached passwords policy

For this step, you must create an account on Appwrite Cloud or have a self-hosted instance configured as in the previous step.

  1. Open your project in the Appwrite Console.
  2. Navigate to Auth in the sidebar.
  3. Open the Policies tab and select Passwords.
  4. In the Breached passwords card, turn on Check passwords against known data breaches.
  5. Optionally, check Reject breached passwords and Block sign-in with a breached password.
  6. Click Update.

The users table then shows the latest result for each user as a shield icon. A red shield means the password was found in a breach, a green one means it wasn't, and a dash means it has never been checked.

Step 3: Handle breached password errors in your app

When enforcement is on, catch the two error types in your sign-up and sign-in flows. On password_pwned, ask the user to choose a different password. On user_password_reset_required, send the user a password recovery email so they can set a new password.

JavaScript
import { Client, Account, ID } from "appwrite";
const client = new Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
.setProject('<PROJECT_ID>');
const account = new Account(client);
// Sign-up rejected by "Reject breached passwords"
try {
await account.create({
userId: ID.unique(),
email: 'email@example.com',
password: '<PASSWORD>'
});
} catch (error) {
if (error.type === 'password_pwned') {
// Ask the user to choose a different password
}
}
// Sign-in refused by "Block sign-in with a breached password"
try {
await account.createEmailPasswordSession({
email: 'email@example.com',
password: '<PASSWORD>'
});
} catch (error) {
if (error.type === 'user_password_reset_required') {
await account.createRecovery({
email: 'email@example.com',
url: 'https://example.com/recovery'
});
}
}

Step 4: Find users with breached passwords

To notify affected users before you turn on enforcement, query the passwordPwned attribute with the server-side Users API:

JavaScript
import { Client, Users, Query } from 'node-appwrite';
const client = new Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
.setProject('<PROJECT_ID>')
.setKey('<YOUR_API_KEY>');
const users = new Users(client);
const result = await users.list({
queries: [Query.equal('passwordPwned', true)]
});

In a client app, the passwordPwned field on the account returned by account.get() tells you whether the signed-in user's password was flagged.

Read more about Have I Been Pwned and Appwrite Auth

If you would like to learn more about Have I Been Pwned and Appwrite Auth, we have some resources that you should visit:

Technology Partner Program

Building on Appwrite?

Teams and developers who ship integrations, tools, or services on Appwrite can join our partner program for verified catalog placement, co-marketing, training, and engineering support.