mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-15 21:19:39 -05:00
[PR #24821] fix: don't block first-admin signup on stale ENABLE_SIGNUP #115180
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/24821
Author: @Classic298
Created: 5/17/2026
Status: 🔄 Open
Base:
dev← Head:fix/fresh-install-admin-signup📝 Commits (1)
dbd0218fix: don't block first-admin signup on stale ENABLE_SIGNUP📊 Changes
1 file changed (+5 additions, -2 deletions)
View changed files
📝
backend/open_webui/routers/auths.py(+5 -2)📄 Description
Symptom
On a fresh install (zero users) the frontend shows the mandatory "Create Admin Account" onboarding screen, but POST /api/v1/auths/signup returns 403 ACCESS_PROHIBITED ("You do not have permission to access this resource."). Wiping the database does not help when the config layer is backed by Redis (the value survives in the Redis/valkey volume), or when only the user table is cleared (the config row survives in Postgres). The instance is then unrecoverable through the UI.
Root cause
signup_handler() auto-sets request.app.state.config.ENABLE_SIGNUP = False immediately after the first admin is created. That value is persisted by the config layer (the Postgres config table, and Redis when REDIS_URL is set). On a later zero-user database the persisted False is read back, so ENABLE_SIGNUP resolves False even though no users exist. The old gate was:
ENABLE_INITIAL_ADMIN_SIGNUP defaults to False, so with zero users the inner test (has_users or not ENABLE_INITIAL_ADMIN_SIGNUP) is True, and a stale ENABLE_SIGNUP=False trips the outer test, producing a 403 on the only UI path that can create the first admin. The frontend decides to show onboarding purely from user_count == 0, so frontend and backend disagree and the instance bricks.
Change
Split the gate by has_users. Subsequent signups (has_users True) are unchanged: still gated by ENABLE_SIGNUP and ENABLE_LOGIN_FORM. The first user (has_users False, the bootstrap admin the onboarding screen invites) is gated only by the admin-chosen ENABLE_LOGIN_FORM (the documented SSO-only hard-disable) unless ENABLE_INITIAL_ADMIN_SIGNUP is set. It is no longer gated by ENABLE_SIGNUP, which in the zero-user state is never an admin decision but the post-first-admin auto-disable leaking across a database reset.
Why this is safe (full case analysis)
For WEBUI_AUTH the gate has 16 input combinations over (has_users, ENABLE_SIGNUP, ENABLE_LOGIN_FORM, ENABLE_INITIAL_ADMIN_SIGNUP). Old and new are identical in 15 of them:
That state has no legitimate deployment. With the login form enabled and zero users the onboarding form is already served, and the only operator-configurable way to keep the first signup closed (SSO-only: ENABLE_LOGIN_FORM=False, optionally with ENABLE_INITIAL_ADMIN_SIGNUP) is preserved byte for byte. ENABLE_SIGNUP=False with zero users is not an operator choice, it is the automatic post-first-admin disable, so the old behaviour there was purely a brick with no recovery path. No security control is weakened: ENABLE_LOGIN_FORM and ENABLE_INITIAL_ADMIN_SIGNUP keep their exact meaning, and the WEBUI_AUTH=False path is untouched.
This is not Redis-specific: it reproduces with Redis disabled through the Postgres config table alone (clear the user table, keep the config row).
Verification
Drove the real signup endpoint across a 10-case matrix on freshly migrated databases, including the full end-to-end first-admin creation (returns role=admin, row persisted as admin) and the preserved SSO-only, subsequent-signup and no-auth behaviours. All pass
Contributor License Agreement
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.