Skip to content

feat(plugin-auth): reject breached passwords via HIBP (ADR-0069 D1, P1)#2361

Merged
os-zhuang merged 1 commit into
mainfrom
auth/adr-0069-hibp
Jun 27, 2026
Merged

feat(plugin-auth): reject breached passwords via HIBP (ADR-0069 D1, P1)#2361
os-zhuang merged 1 commit into
mainfrom
auth/adr-0069-hibp

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Implements the first slice of ADR-0069 (enterprise authentication hardening) — tracking issue #2281 — and establishes the enforcement-wired pattern template the rest of the ADR copies.

What

Adds a password_reject_breached auth setting (default off) wired end-to-end to better-auth's native haveibeenpwned plugin: a k-anonymity range check on sign-up / change-password / reset-password. The plaintext password never leaves the process (only the first 5 SHA-1 hex chars hit api.pwnedpasswords.com).

The trace — manifest setting → bindAuthSettings patch → applyConfigPatchbuildPluginList gate → live enforcement — is the seam every subsequent ADR-0069 item reuses.

File Change
packages/spec/.../auth-config.zod.ts new passwordRejectBreached flag on AuthPluginConfigSchema
packages/services/service-settings/.../auth.manifest.ts "Reject breached passwords" toggle in the password-policy group (global, manage_platform_settings)
packages/plugins/plugin-auth/src/auth-plugin.ts bindAuthSettings maps the setting into plugin config
packages/plugins/plugin-auth/src/auth-manager.ts buildPluginList gates + mounts haveIBeenPwned (env OS_AUTH_PASSWORD_REJECT_BREACHED wins over config, mirroring OS_AUTH_TWO_FACTOR)
packages/cli/src/commands/serve.ts surface the knob in the serve boot config alongside twoFactor

Why this slice first

Per the issue's recommendation: HIBP is native (ships in better-auth 1.6.18, no new dep), stateless (no identity columns / migration / hot-path session logic), and its default check paths already match ADR-0069 D1. Lowest-risk, highest-value, and a clean template.

ADR-0049 compliance

The toggle ships with its enforcement — no false surface. Default-off and additive, so existing environments are unchanged on upgrade. No new identity fields are added (the [custom] D1 items — complexity / expiry / history — land in follow-up PRs that actually read them).

Verification

  • Unit: 102/102 plugin-auth + 128/128 service-settings green
  • Build: spec / service-settings / plugin-auth (incl. strict DTS) / cli green
  • Live dogfood (showcase, both sides of the gate):
    • toggle ON → the same breached password Password123! is intercepted by the HIBP plugin on /sign-up/email (fail-closed when the corpus is unreachable)
    • toggle OFF → the same breached password is accepted (HTTP 200)

Out of scope (follow-up ADR-0069 PRs)

D1 [custom] complexity / expiry / history; D2 lockout + rate-limit; D3 enforced MFA; D7 identity fields; P2 sessions / IP allowlist / OIDC trust-list; P3 SAML.

🤖 Generated with Claude Code

First slice of ADR-0069 (enterprise authentication hardening) and the
enforcement-wired pattern template the rest of the ADR copies. Adds a
`password_reject_breached` auth setting (default off) wired end-to-end to
better-auth's native `haveibeenpwned` plugin — a k-anonymity range check on
sign-up / change / reset; the plaintext password never leaves the process.

- spec: `passwordRejectBreached` flag on AuthPluginConfigSchema.
- service-settings: "Reject breached passwords" toggle in the auth manifest
  password-policy group (global scope, manage_platform_settings).
- plugin-auth: bindAuthSettings maps the setting into plugin config;
  buildPluginList gates + mounts haveIBeenPwned (env
  OS_AUTH_PASSWORD_REJECT_BREACHED wins over config, mirroring twoFactor).
- cli: surface the knob in the serve boot config.

Default-off and additive (no upgrade behavior change). Per ADR-0049 the
toggle ships with its enforcement — no false surface; no new identity fields
(the [custom] D1 items land in follow-ups).

Verified: 102 plugin-auth + 128 service-settings unit tests green; spec /
service-settings / plugin-auth (incl. DTS) / cli build green; live dogfood —
with the toggle ON the HIBP plugin intercepts /sign-up/email (fail-closed when
the corpus is unreachable), with it OFF the same breached password is accepted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 27, 2026 12:21pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:system tests tooling size/m labels Jun 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/cli, @objectstack/plugin-auth, packages/services, @objectstack/spec.

98 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/cli, packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/cli, @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/cli, @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli, @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/spec)
  • content/docs/guides/auth-sso.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/authentication.mdx (via @objectstack/cli, @objectstack/plugin-auth)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/external-datasources.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/cli, packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via @objectstack/cli, @objectstack/plugin-auth, packages/services, @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/plugin-auth, @objectstack/spec)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/project-scoping.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/cli, packages/services, packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via packages/cli, @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/guides/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via packages/services, @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/objectos/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth, @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:system size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant