Files
media-player-mixed/media_server/auth.py
alexei.dolgolyov 67a89e8349 Initial commit: Media server and Home Assistant integration
- FastAPI server for Windows media control via WinRT/SMTC
- Home Assistant custom integration with media player entity
- Script button entities for system commands
- Position tracking with grace period for track skip handling
- Server availability detection in HA entity

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 13:08:40 +03:00

112 lines
3.2 KiB
Python

"""Authentication middleware and utilities."""
from typing import Optional
from fastapi import Depends, HTTPException, Query, Request, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from .config import settings
security = HTTPBearer(auto_error=False)
async def verify_token(
request: Request,
credentials: HTTPAuthorizationCredentials = Depends(security),
) -> str:
"""Verify the API token from the Authorization header.
Args:
request: The incoming request
credentials: The bearer token credentials
Returns:
The validated token
Raises:
HTTPException: If the token is missing or invalid
"""
if credentials is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authentication token",
headers={"WWW-Authenticate": "Bearer"},
)
if credentials.credentials != settings.api_token:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication token",
headers={"WWW-Authenticate": "Bearer"},
)
return credentials.credentials
class TokenAuth:
"""Dependency class for token authentication."""
def __init__(self, auto_error: bool = True):
self.auto_error = auto_error
async def __call__(
self,
request: Request,
credentials: HTTPAuthorizationCredentials = Depends(security),
) -> str | None:
"""Verify the token and return it or raise an exception."""
if credentials is None:
if self.auto_error:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authentication token",
headers={"WWW-Authenticate": "Bearer"},
)
return None
if credentials.credentials != settings.api_token:
if self.auto_error:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication token",
headers={"WWW-Authenticate": "Bearer"},
)
return None
return credentials.credentials
async def verify_token_or_query(
credentials: HTTPAuthorizationCredentials = Depends(security),
token: Optional[str] = Query(None, description="API token as query parameter"),
) -> str:
"""Verify the API token from header or query parameter.
Useful for endpoints that need to be accessed via URL (like images).
Args:
credentials: The bearer token credentials from header
token: Token from query parameter
Returns:
The validated token
Raises:
HTTPException: If the token is missing or invalid
"""
# Try header first
if credentials is not None:
if credentials.credentials == settings.api_token:
return credentials.credentials
# Try query parameter
if token is not None:
if token == settings.api_token:
return token
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing or invalid authentication token",
headers={"WWW-Authenticate": "Bearer"},
)