Reject breached credentials during sign-up and password updates.
Password security
Better Auth · Const
The haveIBeenPwned plugin blocks passwords found in known data breaches. It uses the Have I Been Pwned API with a privacy-preserving hash-prefix lookup.
The plugin checks passwords against the Have I Been Pwned breach database during relevant Better Auth password flows. It uses k-anonymity by sending only the first five characters of the password's SHA-1 hash, and exposes a server-side helper for custom flows.
haveIBeenPwned(options?)| Name | Type | Description |
|---|---|---|
options | HaveIBeenPwnedOptions | undefined | Optional configuration object; its enabled option controls whether password checks run and defaults to true. |
A Better Auth plugin instance configured to check passwords against known breaches.
import { betterAuth } from "better-auth";
import { haveIBeenPwned } from "better-auth/plugins";
export const auth = betterAuth({
plugins: [haveIBeenPwned()]
});Adds compromised-password checks to Better Auth account creation and password updates.
Password security
Custom authentication flows
Non-production environments
The plugin prevents compromised passwords during account creation and password updates. It reports the PASSWORD_COMPROMISED error code when a rejected password is submitted.
Follow-up: How is the password protected during the external lookup? Only the first five characters of its SHA-1 hash are sent; the complete password is not transmitted.
Call isPasswordCompromised with a password in a server-side flow that does not use Better Auth endpoints. The helper returns whether the password appears in the breach database.
Follow-up: What failure behavior should callers account for? The helper can throw an APIError if the breach-checking service cannot complete the request.
Pass enabled to haveIBeenPwned to control whether checks run. Its default is true, so setting it from the production environment can skip checks in development or testing.
Follow-up: What privacy property remains when enabled? The API receives only the first five hash characters, never the full password.
isPasswordCompromisedPASSWORD_COMPROMISEDenabled