open-notebook / api /auth.py
baveshraam's picture
FIX: SurrealDB 2.0 migration syntax and Frontend/CORS link
f871fed
import os
from typing import Optional
from fastapi import HTTPException, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
class PasswordAuthMiddleware(BaseHTTPMiddleware):
"""
Middleware to check password authentication for all API requests.
Only active when OPEN_NOTEBOOK_PASSWORD environment variable is set.
"""
def __init__(self, app, excluded_paths: Optional[list] = None):
super().__init__(app)
self.password = os.environ.get("OPEN_NOTEBOOK_PASSWORD")
self.excluded_paths = excluded_paths or ["/", "/health", "/docs", "/openapi.json", "/redoc"]
async def dispatch(self, request: Request, call_next):
# Skip authentication if no password is set
if not self.password:
return await call_next(request)
# Skip authentication for excluded paths
if request.url.path in self.excluded_paths:
return await call_next(request)
# Skip authentication for CORS preflight requests (OPTIONS)
if request.method == "OPTIONS":
return await call_next(request)
# Check authorization header
auth_header = request.headers.get("Authorization")
if not auth_header:
return JSONResponse(
status_code=401,
content={"detail": "Missing authorization header"},
headers={"WWW-Authenticate": "Bearer"}
)
# Expected format: "Bearer {password}"
try:
scheme, credentials = auth_header.split(" ", 1)
if scheme.lower() != "bearer":
raise ValueError("Invalid authentication scheme")
except ValueError:
return JSONResponse(
status_code=401,
content={"detail": "Invalid authorization header format"},
headers={"WWW-Authenticate": "Bearer"}
)
# Check password
if credentials != self.password:
return JSONResponse(
status_code=401,
content={"detail": "Invalid password"},
headers={"WWW-Authenticate": "Bearer"}
)
# Password is correct, proceed with the request
response = await call_next(request)
return response
# Optional: HTTPBearer security scheme for OpenAPI documentation
security = HTTPBearer(auto_error=False)
def check_api_password(credentials: Optional[HTTPAuthorizationCredentials] = None) -> bool:
"""
Utility function to check API password.
Can be used as a dependency in individual routes if needed.
"""
password = os.environ.get("OPEN_NOTEBOOK_PASSWORD")
# No password set, allow access
if not password:
return True
# No credentials provided
if not credentials:
raise HTTPException(
status_code=401,
detail="Missing authorization",
headers={"WWW-Authenticate": "Bearer"},
)
# Check password
if credentials.credentials != password:
raise HTTPException(
status_code=401,
detail="Invalid password",
headers={"WWW-Authenticate": "Bearer"},
)
return True