Make auth toggle a settings option instead of env var
Some checks failed
CI / style (push) Has been cancelled
CI / build-client (push) Has been cancelled
CI / build-tester (push) Has been cancelled
CI / build-amd64 (push) Has been cancelled
CI / test (cockroachdb) (push) Has been cancelled
CI / test (mariadb) (push) Has been cancelled
CI / test (postgres) (push) Has been cancelled
CI / test (sqlite) (push) Has been cancelled
CI / build-arm64 (push) Has been cancelled
CI / build-armv7 (push) Has been cancelled
CI / publish-images (push) Has been cancelled
CI / publish-release (push) Has been cancelled
Issue Manager / issue-manager (push) Has been cancelled

- Auth enabled state now stored in database setting (auth_enabled)
- Add POST /auth/toggle endpoint to enable/disable auth from UI
- Add auth toggle section to Settings > General page
- Enabling auth without users prompts to create first admin
- Disabling auth requires admin password confirmation
- Auth setting cached in memory and loaded on startup

Removes need for SPOOLMAN_AUTH_ENABLED env var

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 01:01:14 -06:00
parent e782b89929
commit f63f70ce86
7 changed files with 316 additions and 7 deletions

View File

@@ -1,5 +1,6 @@
"""Authentication utilities and dependencies."""
import json
import logging
import os
import secrets
@@ -31,10 +32,35 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# OAuth2 scheme - auto_error=False allows unauthenticated access when auth is disabled
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/v1/auth/login", auto_error=False)
# Cached auth enabled state (loaded from database on startup)
_auth_enabled_cache: bool = False
def is_auth_enabled() -> bool:
"""Check if authentication is enabled via environment variable."""
return os.environ.get("SPOOLMAN_AUTH_ENABLED", "false").lower() in ("true", "1", "yes")
"""Check if authentication is enabled (from cached database setting)."""
return _auth_enabled_cache
def set_auth_enabled_cache(enabled: bool) -> None:
"""Update the cached auth enabled state."""
global _auth_enabled_cache
_auth_enabled_cache = enabled
logger.info("Auth enabled cache updated: %s", enabled)
async def load_auth_enabled_from_db(db: AsyncSession) -> bool:
"""Load auth_enabled setting from database and update cache."""
from spoolman.settings import SETTINGS
setting = await db.get(models.Setting, "auth_enabled")
if setting is not None:
enabled = json.loads(setting.value)
else:
# Use default from settings definition
enabled = json.loads(SETTINGS["auth_enabled"].default)
set_auth_enabled_cache(enabled)
return enabled
class Role(str, Enum):