Type Definitions

This module contains type definitions and data structures used throughout the auth-middleware library. These types provide type safety and clear interfaces for authentication and authorization components.

Core Types

User Types

The library defines several user-related types to represent authenticated users:

from typing import List, Optional, Dict, Any
from dataclasses import dataclass

@dataclass
class User:
    """Represents an authenticated user."""
    id: str
    name: str
    email: str
    groups: List[str] = None
    permissions: List[str] = None
    extra: Dict[str, Any] = None

Provider Types

Authentication providers implement the following interfaces:

from abc import ABC, abstractmethod
from typing import Protocol

class AuthenticationProvider(Protocol):
    """Protocol for authentication providers."""

    async def validate_token(self, token: str) -> Dict[str, Any]:
        """Validate a token and return user information."""
        ...

    async def get_user_info(self, token_data: Dict[str, Any]) -> User:
        """Extract user information from token data."""
        ...

Configuration Types

Provider settings and configuration types:

from pydantic import BaseModel
from typing import Optional

class ProviderSettings(BaseModel):
    """Base settings for authentication providers."""

    class Config:
        extra = "forbid"  # Prevent additional fields

class JWTProviderSettings(ProviderSettings):
    """Settings for JWT authentication provider."""
    secret_key: str
    algorithm: str = "HS256"
    issuer: Optional[str] = None
    audience: Optional[str] = None
    verify_signature: bool = True
    verify_exp: bool = True
    verify_iat: bool = True
    leeway: int = 0

Token Types

JWT Token Structure

Standard JWT token claims structure:

from typing import Union, List, Dict, Any
from datetime import datetime

class JWTClaims:
    """Standard JWT claims."""

    # Standard claims
    iss: Optional[str] = None      # Issuer
    sub: Optional[str] = None      # Subject (user ID)
    aud: Union[str, List[str]] = None  # Audience
    exp: Optional[datetime] = None  # Expiration time
    iat: Optional[datetime] = None  # Issued at
    nbf: Optional[datetime] = None  # Not before
    jti: Optional[str] = None      # JWT ID

    # Custom claims
    name: Optional[str] = None
    email: Optional[str] = None
    groups: List[str] = []
    permissions: List[str] = []
    custom_claims: Dict[str, Any] = {}

Authentication Context

Request Context Types

Types for managing authentication context in requests:

from starlette.requests import Request
from typing import Optional

class AuthenticatedRequest(Request):
    """Extended request with authentication context."""

    @property
    def current_user(self) -> Optional[User]:
        """Get the current authenticated user."""
        return getattr(self.state, 'current_user', None)

    @property
    def auth_token(self) -> Optional[str]:
        """Get the authentication token."""
        return getattr(self.state, 'auth_token', None)

    @property
    def is_authenticated(self) -> bool:
        """Check if request is authenticated."""
        return self.current_user is not None

Middleware Types

Types for middleware configuration:

from enum import Enum
from typing import Callable, Awaitable

class AuthMode(Enum):
    """Authentication modes."""
    REQUIRED = "required"      # Authentication required for all endpoints
    OPTIONAL = "optional"      # Authentication optional
    DISABLED = "disabled"      # Authentication disabled

class AuthMiddlewareConfig:
    """Configuration for authentication middleware."""

    auth_provider: AuthenticationProvider
    auth_mode: AuthMode = AuthMode.REQUIRED
    excluded_paths: List[str] = []
    included_paths: List[str] = []
    token_header: str = "Authorization"
    token_prefix: str = "Bearer"

Exception Types

Error and Exception Types

from typing import Optional, List

class AuthError:
    """Base authentication error."""

    def __init__(
        self,
        message: str,
        error_code: Optional[str] = None,
        details: Optional[Dict[str, Any]] = None
    ):
        self.message = message
        self.error_code = error_code
        self.details = details or {}

class ValidationError(AuthError):
    """Token validation error."""

    def __init__(
        self,
        message: str,
        token: Optional[str] = None,
        claims: Optional[Dict[str, Any]] = None
    ):
        super().__init__(message)
        self.token = token
        self.claims = claims

Provider-Specific Types

AWS Cognito Types

class CognitoUser(User):
    """Cognito-specific user representation."""

    cognito_username: str
    user_pool_id: str
    client_id: str
    token_use: str  # 'access' or 'id'
    cognito_groups: List[str] = []
    custom_attributes: Dict[str, str] = {}

Azure Entra ID Types

class EntraIdUser(User):
    """Azure Entra ID user representation."""

    object_id: str
    tenant_id: str
    app_id: str
    roles: List[str] = []
    scopes: List[str] = []
    upn: Optional[str] = None  # User Principal Name

Validation Types

Validation Rules

from typing import Callable, Any

ValidationRule = Callable[[Any], bool]

class PermissionRule:
    """Permission validation rule."""

    def __init__(
        self,
        required_permissions: List[str],
        operation: str = "any"  # "any" or "all"
    ):
        self.required_permissions = required_permissions
        self.operation = operation

    def validate(self, user_permissions: List[str]) -> bool:
        if self.operation == "all":
            return all(perm in user_permissions for perm in self.required_permissions)
        else:  # "any"
            return any(perm in user_permissions for perm in self.required_permissions)

class GroupRule:
    """Group membership validation rule."""

    def __init__(
        self,
        required_groups: List[str],
        operation: str = "any"
    ):
        self.required_groups = required_groups
        self.operation = operation

    def validate(self, user_groups: List[str]) -> bool:
        if self.operation == "all":
            return all(group in user_groups for group in self.required_groups)
        else:  # "any"
            return any(group in user_groups for group in self.required_groups)

Usage Examples

Type Hints in Application Code

from fastapi import FastAPI, Depends
from auth_middleware.types import User, AuthenticatedRequest
from auth_middleware import get_current_user

app = FastAPI()

@app.get("/profile")
async def get_profile(
    request: AuthenticatedRequest,
    user: User = Depends(get_current_user)
) -> Dict[str, Any]:
    return {
        "user_id": user.id,
        "name": user.name,
        "email": user.email,
        "groups": user.groups,
        "is_authenticated": request.is_authenticated
    }

Custom Provider Implementation

from auth_middleware.types import AuthenticationProvider, User, ProviderSettings

class CustomProviderSettings(ProviderSettings):
    api_key: str
    base_url: str = "https://api.example.com"

class CustomProvider(AuthenticationProvider):
    def __init__(self, settings: CustomProviderSettings):
        self.settings = settings

    async def validate_token(self, token: str) -> Dict[str, Any]:
        # Custom validation logic
        ...

    async def get_user_info(self, token_data: Dict[str, Any]) -> User:
        # Extract user information
        return User(
            id=token_data["user_id"],
            name=token_data["name"],
            email=token_data["email"],
            groups=token_data.get("groups", [])
        )

API Reference