From ffb77d7ff21794840b72bf11eb1916e6359cd50d Mon Sep 17 00:00:00 2001 From: Tatlatat Date: Tue, 2 Jun 2026 10:26:26 +0700 Subject: [PATCH] fix(auth): honor AUTH_ENABLED=false on owner-scoped endpoints (no /login loop) (#880) When the operator sets AUTH_ENABLED=false, three owner-scoped endpoints still returned 401 (api/models, api/research/*, api/email/*), so the front-end redirected the browser to /login and the app was unusable despite auth being turned off. require_user() in src/auth_helpers.py already documents and honors this contract (issue #622) via 'if _auth_disabled(): return ""', but these endpoints did their own get_current_user/is_configured check without it. Make _require_user (research), the /api/models anti-leak guard, and email_helpers._require_auth consult _auth_disabled() and let anonymous through (owner='') only when the operator explicitly disabled auth. The 401 protection is fully intact when AUTH_ENABLED=true. Verified end-to-end: with AUTH_ENABLED=false the SPA now loads instead of bouncing to /login. --- routes/email_helpers.py | 4 +++- routes/model_routes.py | 4 ++-- routes/research_routes.py | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/routes/email_helpers.py b/routes/email_helpers.py index c14fd8c..cf02ced 100644 --- a/routes/email_helpers.py +++ b/routes/email_helpers.py @@ -33,7 +33,7 @@ from fastapi import Query, HTTPException, Request from pydantic import BaseModel from typing import Optional, List -from src.auth_helpers import get_current_user +from src.auth_helpers import _auth_disabled, get_current_user from src.secret_storage import decrypt as _decrypt logger = logging.getLogger(__name__) @@ -152,6 +152,8 @@ def _require_auth(request: Request) -> str: u = get_current_user(request) if u: return u + if _auth_disabled(): + return "" auth_mgr = getattr(request.app.state, "auth_manager", None) if auth_mgr is not None and getattr(auth_mgr, "is_configured", False): raise HTTPException(401, "Not authenticated") diff --git a/routes/model_routes.py b/routes/model_routes.py index 770871d..858c236 100644 --- a/routes/model_routes.py +++ b/routes/model_routes.py @@ -22,7 +22,7 @@ from src.endpoint_resolver import ( build_models_url, build_headers, ) -from src.auth_helpers import owner_filter +from src.auth_helpers import _auth_disabled, owner_filter logger = logging.getLogger(__name__) @@ -586,7 +586,7 @@ def setup_model_routes(model_discovery): # list to unauthenticated callers. try: auth_mgr = getattr(request.app.state, "auth_manager", None) - if not owner and auth_mgr is not None and getattr(auth_mgr, "is_configured", False): + if not owner and not _auth_disabled() and auth_mgr is not None and getattr(auth_mgr, "is_configured", False): raise HTTPException(401, "Not authenticated") except HTTPException: raise diff --git a/routes/research_routes.py b/routes/research_routes.py index fe1d855..c075002 100644 --- a/routes/research_routes.py +++ b/routes/research_routes.py @@ -13,7 +13,7 @@ from fastapi import APIRouter, HTTPException, Query, Request from fastapi.responses import HTMLResponse, StreamingResponse from pydantic import BaseModel, Field from src.endpoint_resolver import resolve_endpoint -from src.auth_helpers import get_current_user +from src.auth_helpers import _auth_disabled, get_current_user _SESSION_ID_RE = re.compile(r"^[a-zA-Z0-9-]{1,128}$") @@ -58,6 +58,8 @@ def setup_research_routes(research_handler, session_manager=None) -> APIRouter: verify the session belongs to this user.""" user = get_current_user(request) if not user: + if _auth_disabled(): + return "" raise HTTPException(401, "Not authenticated") return user