from __future__ import annotations import hmac from dataclasses import dataclass from typing import Annotated import jwt from fastapi import Header, HTTPException, status from agent_platform.config import get_settings @dataclass(frozen=True, slots=True) class UserIdentity: user_id: str email: str name: str role: str def verify_service_bearer(authorization: str | None, expected: str) -> None: if not expected: raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Service secret is not configured") scheme, _, token = (authorization or "").partition(" ") if scheme.lower() != "bearer" or not hmac.compare_digest(token, expected): raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid service credentials") def decode_openwebui_identity(token: str | None, secret: str) -> UserIdentity: if not secret: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Identity verification is unavailable", ) if not token: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing signed user identity") try: claims = jwt.decode( token, secret, algorithms=["HS256"], issuer="open-webui", options={"require": ["sub", "iss", "iat", "exp"]}, ) except jwt.PyJWTError as exc: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid signed user identity") from exc user_id = str(claims.get("sub", "")).strip() if not user_id: raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Signed identity has no subject") return UserIdentity( user_id=user_id, email=str(claims.get("email", "")), name=str(claims.get("name", "")), role=str(claims.get("role", "user")), ) def require_gateway_identity( authorization: Annotated[ str | None, Header(alias="Authorization", include_in_schema=False), ] = None, user_jwt: Annotated[ str | None, Header(alias="X-OpenWebUI-User-Jwt", include_in_schema=False), ] = None, ) -> UserIdentity: settings = get_settings() verify_service_bearer(authorization, settings.internal_gateway_key) return decode_openwebui_identity(user_jwt, settings.openwebui_forward_jwt_secret)