The entries below document the retired pre-1.0 standalone package only. They may mention its former multimodal dependency, Doctrine adapters, controllers, or migrations; those are not current 1.0 behavior or requirements.
Version20260722120000 (SEC-30 token indexes) no longer touches the
$schema argument at all. v0.1.1 stopped mutating it but still read it
($schema->hasTable()); that read alone realizes Doctrine's LazySchemaDiffProvider
and triggers the same full-schema Comparator::compareSchemas(), which still aborts
with a spurious TableDoesNotExist on an unrelated host table when the host schema
has drift. The migration now inspects the live connection's schema manager (scoped to
the token tables) for idempotency and emits raw CREATE INDEX — the lazy diff is
never realized.Version20260722120000 (SEC-30 token indexes) no longer mutates the
Schema object. Calling $table->addIndex() made Doctrine compute a full-schema
diff, which introspects every table of the host application and aborts on any
unrelated schema drift (TableDoesNotExist on a host table). It now emits raw
CREATE INDEX via addSql() while still reading $schema for idempotency — same
fix already applied to Version20260621120000. (Superseded by 0.1.2: reading
$schema is itself enough to trigger the abort.)betterauth/multimodal-php ^0.1 (was ~0.0.3), which carries the
matching core security hardening.Hardening pass from the 2026-07-22 security audit. All changes are test-backed.
CookieTokenExtractor is no longer in the default
token-extractor chain (cookie auth is now opt-in), and CsrfProtectionSubscriber
enforces a double-submit X-CSRF-TOKEN header on every state-changing request that
carries the auth cookie (any path/mode); Bearer and cookie-less requests are exempt.
Breaking for apps relying on implicit cookie auth — re-add the extractor and keep
the CSRF subscriber enabled.FlexInstaller uses Process (argument array) instead of exec();
the signing secret is written to .env.local (chmod 0600), not the committed .env.user_id/expires_at), guest-session
creation rate-limited per IP, TotpProvider wired with a rate limiter, PII masked in
password-reset logs, multi_tenant.enabled defaults to false (aligned with the
config template).Re-release of 0.0.22. The 0.0.22 release automation failed on a locked tag, so its git tag (while retained and installable) has no published GitHub release; this patch re-issues the same dependency-constraint fix under a clean tag. No code changes since 0.0.22.
betterauth/multimodal-php now allows the tagged 0.0.x line
(~0.0.3 || dev-main). The previous ^0.1 matched no published 0.0.x release, so a
tagged install could only resolve the Core package from the dev-main branch.id (decoupled from the secret
token) usable as a safe revocation/listing handle. DoctrineSessionRepository implements
findById() / deleteById() and persists the id verbatim (never hashed).
SessionController::list() exposes id and resolves the current flag from the bearer
token via AuthManager::validateSession() (the previous token comparison was always
false once tokens became hashed at rest).login/login2fa now verify credentials via AuthManager::verifyCredentials() and
create the session/tokens via completeSignIn(), removing the redundant second password
verification while keeping the 2FA gate before any session/token is created.Version20260621120000: adds a nullable, unique id column to sessions
and backfills an opaque id for every pre-existing row.SymfonyMailerEmailSender.DoctrineUserRepository::create()/update() now read the canonical password_hash key.
Sign-up on the Doctrine path persisted the password as NULL, so every subsequent login
failed with InvalidCredentialsException — now fixed.400 in session-only mode).SessionController::list() guards validateSession() by session mode, so listing no
longer errors in pure API mode.CredentialsController::login() and login2fa() are
now rate-limited (5 attempts / 15 min per IP+email) before the manual password/TOTP
checks. Previously the rate limiter was only reached after a successful password, leaving
password and TOTP brute-force unbounded.callbackUrl against the trusted frontend origin before
embedding it in the emailed link (returns 400 on a foreign host).DoctrineSessionRepository stores sha256(token) and
looks up by hash. A DB read no longer yields usable session tokens.DoctrineTotpRepository encrypts the TOTP seed with
AES-256-GCM, keyed from %better_auth.secret%.replaced_by hashed for consistency (no raw replacement token stored).cookie_secure / cookie_http_only / cookie_same_site
are now part of the configuration tree (the recipe shipped them but they were undeclared,
which could break boot or silently drop them). Secure defaults: true / true / lax.refresh_token
(it is now null — session mode has no separate rotatable credential).ke***[@domain](https://github.com/domain)) to avoid leaking PII into centralized logs.QueryParameterTokenExtractor documentation strengthened; it remains off by default
(not part of the default ChainTokenExtractor).composer update):
enc:v1: marker distinguishes encrypted from legacy values).composer install hook is intentionally not used: dependency composer
scripts do not run in the consumer project, and auto-running DB migrations at build time
would break CI. The self-migrating repositories achieve the same result safely.BETTER_AUTH_SECRET stable — rotating it makes already-encrypted TOTP secrets
unreadable.How can I help you explore Laravel packages today?