Repository navigation
Conversation
…can log in POST /auth/register/form (what the register page posts to) inserted auth_user but not the auth_account credential row Better Auth reads the password from. Registration returned 200, the first user was even made admin, and every sign-in then failed with "Invalid email or password". The JSON /auth/register already wrote both rows; the form handler now does the same, in one batch. The first user is the admin, and admin access is RBAC-backed. A failed first boot can leave the system roles unseeded (#1017), and addUserRoleByName then silently does nothing. So for the first account the form now seeds the document types and system roles first (idempotent, same as /auth/seed-admin) and checks the admin role actually landed. If it can't be assigned, the new rows are removed and the error is reported, so a retry works instead of hitting "email already exists". Optional custom profile fields are saved after that; a failure there is logged rather than failing a working account. Docs: the deployment, configuration, troubleshooting and core-plugin pages said the ADMIN_EMAIL / ADMIN_PASSWORD secrets create the admin at bootstrap. Nothing reads them. They now say the first account registered becomes the admin, and drop the "create admin via API" example (the JSON route always creates a viewer). E2E 113 registers through the real page and logs in. It waits out spec 37's short registration-disabled windows on the shared preview DB instead of toggling the setting. Refs #1054
This was referenced Oct 13, 2026
mmcintosh
marked this pull request as ready for review
October 13, 2026 20:13
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
The register page posts to
POST /auth/register/form(htmx), not to the JSON/auth/register. The form handler insertedauth_userbut never theauth_accountcredential row that Better Auth signs in with.As a result:
Credential account not found), until a later full bootstrap happened to backfill the row (with the KV marker, up to 24 hours).The JSON route already wrote both rows. Only the path the UI uses was broken.
The deployment docs made it worse. They say the
ADMIN_EMAIL/ADMIN_PASSWORDsecrets create the admin at bootstrap, and nothing in the code reads them.Refs #1054 (reported in detail by elpastiche on that issue).
Changes
routes/auth.ts,POST /auth/register/form:auth_userand the credential row in onedb.batch, exactly as the JSON route does;/auth/seed-adminmakes;docs/deployment.md.ADMIN_EMAIL/ADMIN_PASSWORD.Testing
auth-register-form.integration.test.ts(new, 6 tests): real SQLite, then sign-in through a real Better Auth instance.On
main's handler, 5 of the 6 fail; the wrong-password case is the control and passes either way. The tests also pass on Better Auth 1.7.7 (fix(auth): move to Better Auth 1.7.7 and better-auth-cloudflare 0.4.1 #1103).Unit Tests
E2E Tests
113-register-form-login.spec.ts(@auth). It registers through the real page, then logs in throughPOST /auth/login, and a wrong password gets 401. It waits out spec 37 switching registration off on the shared preview database instead of toggling the setting itself.Screenshots/Videos
N/A. The register page looks the same; the change is what the server writes. The docs changes are text only.
Checklist