from typing import Any from fastapi.security import HTTPAuthorizationCredentials from jwtauth import JWTAuth from jwtauth.exceptions import JWTAuthError from jwtauth.utils import get_default_issuer, get_default_jwks_url from starlette.requests import Request from fansifter_common.auth.exceptions import NotAuthenticated from fansifter_common.auth.identity import Identity from fansifter_common.constants import ( CLAIM_ORCHARD_IDENTITY_ID, DEFAULT_BRAND, FAN_RESPONSE_PROD_AUDIENCE, FAN_RESPONSE_QA_AUDIENCE, JWT_BRAND, JWT_INTERNAL_EMPLOYEE, JWT_USER_METADATA, PROD_ENVIRONMENT, ) INTERNAL_EMPLOYEES = [ "848e9f3a-c7e2-4207-bddc-7fd5d07674cd", # owherry+testsme@sonymusic-pde.com "49732c21-86ac-4b05-8383-7f6c02db1133", # jfowler+demo@theorchard.com "190d018d-5133-4f72-abb2-c3c584404f63", # sheena.chatterjee+demo@sonymusic-pde.com "19c47500-a71f-4a9c-a698-cd837cc144c7", # fansifter-e2e-7123-34514@theorchard.io ] async def authenticate_identity( request: Request, credentials: HTTPAuthorizationCredentials | None, jwt_auth: JWTAuth, ) -> Identity: token: dict[str, Any] | None = request.scope.get("token") if not token and credentials: try: token = await jwt_auth.aget_token(credentials.credentials) except JWTAuthError as exc: raise NotAuthenticated(exc.message) from exc if not token: raise NotAuthenticated("Missing Authorization header.") identity_id: str | None = None grass_data = token.get(JWT_USER_METADATA) if grass_data: identity_id = grass_data.get(CLAIM_ORCHARD_IDENTITY_ID) if not identity_id: raise NotAuthenticated(f"Missing token {CLAIM_ORCHARD_IDENTITY_ID} claim.") if identity_id in INTERNAL_EMPLOYEES: is_internal_employee = True else: is_internal_employee = token.get(JWT_INTERNAL_EMPLOYEE) or False return Identity( id=identity_id, brand=token.get(JWT_BRAND) or DEFAULT_BRAND, is_internal_employee=is_internal_employee, ) def get_fan_response_jwt_auth(environment: str) -> JWTAuth: if environment == PROD_ENVIRONMENT: audience = FAN_RESPONSE_PROD_AUDIENCE else: audience = FAN_RESPONSE_QA_AUDIENCE return JWTAuth( jwks_url=get_default_jwks_url(environment), audience=[audience], issuer=get_default_issuer(environment), ) async def validate_fan_response_jwt( credentials: HTTPAuthorizationCredentials | None, fan_response_jwt_auth: JWTAuth, ) -> None: if not credentials: raise NotAuthenticated("Missing Authorization header.") try: await fan_response_jwt_auth.aget_token(credentials.credentials) except Exception as exc: raise NotAuthenticated("Invalid JWT token.") from exc