modcomms/backend/app/config.py
michael 321a9ca820 Implement Microsoft MSAL SSO with PKCE flow
Frontend:
- Add @azure/msal-browser and @azure/msal-react packages
- Create authConfig.ts with MSAL configuration for PKCE flow
- Create authService.ts for token acquisition and user info
- Wrap App with MsalProvider in index.tsx
- Replace dummy login with real MSAL loginPopup() in Login.tsx
- Update App.tsx to use useIsAuthenticated/useMsal hooks
- Update Profile.tsx to display real user data from claims
- Update geminiService.ts to include access_token in WebSocket messages
- Update WIPReviewer.tsx to pass msalInstance for auth

Backend:
- Add python-jose and httpx dependencies for JWT verification
- Create auth_service.py with Azure AD JWKS fetching and token verification
- Create auth.py FastAPI dependency for protected REST endpoints
- Update main.py to verify tokens on WebSocket and protect /info endpoint
- Add AZURE_TENANT_ID, AZURE_CLIENT_ID, DISABLE_AUTH to config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-16 08:43:30 -06:00

40 lines
1.5 KiB
Python

import os
from pathlib import Path
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
class Settings:
"""Application settings loaded from environment variables."""
GEMINI_API_KEY: str = os.getenv("GEMINI_API_KEY", "")
CORS_ORIGINS: str = os.getenv("CORS_ORIGINS", "http://localhost:3000")
HOST: str = os.getenv("HOST", "0.0.0.0")
PORT: int = int(os.getenv("PORT", "8000"))
# Reference docs path - defaults to ../reference_docs relative to backend/
_default_ref_docs = Path(__file__).parent.parent.parent / "reference_docs"
REFERENCE_DOCS_PATH: str = os.getenv("REFERENCE_DOCS_PATH", str(_default_ref_docs))
# Azure AD Configuration for token verification
AZURE_TENANT_ID: str = os.getenv("AZURE_TENANT_ID", "")
AZURE_CLIENT_ID: str = os.getenv("AZURE_CLIENT_ID", "")
# Auth bypass for development (set to "true" to skip auth)
DISABLE_AUTH: bool = os.getenv("DISABLE_AUTH", "false").lower() == "true"
def validate(self) -> None:
"""Validate required settings are present."""
if not self.GEMINI_API_KEY:
raise ValueError("GEMINI_API_KEY environment variable is required")
if not self.DISABLE_AUTH:
if not self.AZURE_TENANT_ID:
raise ValueError("AZURE_TENANT_ID environment variable is required (or set DISABLE_AUTH=true)")
if not self.AZURE_CLIENT_ID:
raise ValueError("AZURE_CLIENT_ID environment variable is required (or set DISABLE_AUTH=true)")
settings = Settings()