Fix all 7 launch blockers from security/QA review

SEC-16: Add frontend ports mapping (80:80) to docker-compose.yml
UI-01:  Add routes for Welcome, SettingsIntegrations, MealPlan in App.jsx
SEC-01: Remove traceback leak from auth error responses
SEC-02: Fix require_admin to use is_admin column (was undefined ADMIN_USERNAME)
SEC-03: Add API_TOKEN auth for MCP connector -> backend communication
SEC-04: OAuth state now uses signed JWT tokens (was raw user UUID)
OS-01:  First registered user gets admin immediately during registration

10 files changed, 97 insertions(+), 25 deletions(-)
This commit is contained in:
Claude 2026-06-16 01:50:09 +00:00
parent 50eae17c34
commit 69320e1e82
10 changed files with 97 additions and 25 deletions

View file

@ -13,7 +13,7 @@ from app.config import get_settings
from app.database import get_db
settings = get_settings()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login", auto_error=False)
def hash_password(password: str) -> str:
@ -31,7 +31,7 @@ def create_access_token(user_id: str, expires_delta: timedelta | None = None) ->
async def get_current_user(
token: Annotated[str, Depends(oauth2_scheme)],
token: Annotated[str | None, Depends(oauth2_scheme)],
db: Annotated[AsyncSession, Depends(get_db)],
):
credentials_exception = HTTPException(
@ -39,6 +39,30 @@ async def get_current_user(
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
if not token:
raise credentials_exception
from app.models.user import User
# Check if this is an API token (MCP connector auth)
if settings.api_token and token == settings.api_token:
# Map to the first admin user
result = await db.execute(
select(User).where(User.is_admin == True).order_by(User.created_at.asc()).limit(1)
)
user = result.scalar_one_or_none()
if user is None:
# Fall back to first user if no admin exists yet
result = await db.execute(
select(User).order_by(User.created_at.asc()).limit(1)
)
user = result.scalar_one_or_none()
if user is None:
raise credentials_exception
return user
# Standard JWT validation
try:
payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm])
user_id: str = payload.get("sub")
@ -47,7 +71,6 @@ async def get_current_user(
except JWTError:
raise credentials_exception
from app.models.user import User
result = await db.execute(select(User).where(User.id == uuid.UUID(user_id)))
user = result.scalar_one_or_none()
if user is None: