HIGH logging monitoring failuresfastapibasic auth

Logging Monitoring Failures in Fastapi with Basic Auth

Logging Monitoring Failures in Fastapi with Basic Auth — how this specific combination creates or exposes the vulnerability

When Basic Authentication is used in FastAPI without structured logging and active monitoring, security events that should be surfaced can be missed or rendered useless. Basic Auth sends credentials in an Authorization header on each request; if the server does not log enough context and does not monitor those logs, attackers can operate undetected.

Key gaps appear in three dimensions:

  • Detection: Without logging of authentication successes and failures, you cannot identify brute-force attempts, credential spraying, or reuse of stolen credentials. A missing log line for a 401 means an attacker can try passwords without visibility.
  • Alerting: If logs are not monitored with rules that raise alerts on anomalies (e.g., many 401s from one IP, a single user failing from multiple locations), suspicious behavior escalates to a breach.
  • Forensics: In an incident, poor logs (missing usernames, client IPs, timestamps, paths, and status codes) prevent reconstructing the chain of events. This hinders root cause analysis and compliance reporting.

    These issues are especially relevant because FastAPI does not enforce logging by default; you must add it. An endpoint that uses Basic Auth but lacks audit logs provides a weak defense-in-depth posture, even if authentication itself is technically correct.

    Example of insufficient logging in FastAPI with Basic Auth:

    from fastapi import FastAPI, Depends, HTTPException, status
    from fastapi.security import HTTPBasic, HTTPBasicCredentials
    import logging
    
    logging.basicConfig(level="INFO")
    logger = logging.getLogger(__name__)
    
    app = FastAPI()
    security = HTTPBasic()
    
    USERS = {"alice": "secret123"}
    
    def get_current_user(credentials: HTTPBasicCredentials = Depends(security)):
        correct = USERS.get(credentials.username) == credentials.password
        if not correct:
            # Missing: structured log with username, client host, path, and outcome
            logger.warning("Auth failed")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid credentials",
                headers={"WWW-Authenticate": "Basic"},
            )
        # Missing: success log with username and client context
        return credentials.username
    
    @app.get("/secure")
    def read_secure(user: str = Depends(get_current_user)):
        return {"message": f"Hello {user}"}

    In this example, the logs lack structured fields (username, IP, endpoint, timestamp), making it hard to monitor patterns. Without integrating these logs into a monitoring system that triggers alerts on repeated 401s or impossible travel, the monitoring control is ineffective. middleBrick scans can surface such weaknesses by checking authentication coverage and log-related findings in the unauthenticated attack surface.

Basic Auth-Specific Remediation in Fastapi — concrete code fixes

Remediation focuses on three actions: structured logging of authentication events, rate-limiting to reduce brute-force impact, and ensuring logs contain enough detail for monitoring and forensics. Below are concrete, working examples.

1) Structured logging for auth successes and failures

Log usernames (or a hashed representation), client IP, path, HTTP method, status, and a unique request ID to correlate logs and support alerting.

from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from starlette.middleware.base import BaseHTTPMiddleware
import logging
import time
import uuid

logging.basicConfig(level="INFO", format="%(asctime)s %(levelname)s %(message)s")
logger = logging.getLogger(__name__)

app = FastAPI()
security = HTTPBasic()

USERS = {"alice": "secret123"}

class CorrelationMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
        request.state.correlation_id = str(uuid.uuid4())
        response = await call_next(request)
        return response

app.add_middleware(CorrelationMiddleware)

def get_current_user(credentials: HTTPBasicCredentials = Depends(security), request: Request = None):
    username = credentials.username
    client_host = request.client.host if request and request.client else "unknown"
    req_id = getattr(request.state, "correlation_id", "unknown") if request else "unknown"
    correct = USERS.get(username) == credentials.password
    if not correct:
        logger.warning(
            "auth_failure",
            extra={
                "event": "auth_failure",
                "username": username,
                "client_ip": client_host,
                "method": request.method if request else "unknown",
                "path": request.url.path if request else "unknown",
                "correlation_id": req_id,
            },
        )
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    logger.info(
        "auth_success",
        extra={
            "event": "auth_success",
            "username": username,
            "client_ip": client_host,
            "method": request.method if request else "unknown",
            "path": request.url.path if request else "unknown",
            "correlation_id": req_id,
        },
    )
    return username

@app.get("/secure")
def read_secure(user: str = Depends(lambda r: get_current_user(request=r))):
    return {"message": f"Hello {user}"}

2) Add rate-limiting to mitigate brute-force

Use a simple in-memory store for demonstration; in production, use Redis or a distributed store.

from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from collections import defaultdict
import time

app = FastAPI()
security = HTTPBasic()

USERS = {"alice": "secret123"}
failed_attempts = defaultdict(list)
RATE_LIMIT_WINDOW = 60  # seconds
MAX_ATTEMPTS = 5

def is_rate_limited(client_ip: str) -> bool:
    now = time.time()
    attempts = failed_attempts[client_ip]
    # clean old attempts
    failed_attempts[client_ip] = [t for t in attempts if now - t < RATE_LIMIT_WINDOW]
    return len(failed_attempts[client_ip]) >= MAX_ATTEMPTS

def get_current_user(credentials: HTTPBasicCredentials = Depends(security), request: Request = None):
    client_ip = request.client.host if request and request.client else "unknown"
    if is_rate_limited(client_ip):
        raise HTTPException(status_code=429, detail="Too many requests")
    correct = USERS.get(credentials.username) == credentials.password
    if not correct:
        failed_attempts[client_ip].append(time.time())
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid credentials",
            headers={"WWW-Authenticate": "Basic"},
        )
    # success: optionally clear failed attempts
    failed_attempts[client_ip].clear()
    return credentials.username

3) Monitoring and alerting guidance

Ensure your logging pipeline indexes fields like event, username, and client_ip so you can create alerts such as: trigger if >10 auth_failure events from the same client_ip within 5 minutes. Regularly review logs for patterns like credential reuse across endpoints, which basic auth does not protect against replay without additional transport protections.

middleBrick can be used in the Pro plan for continuous monitoring of such authentication surfaces, and the GitHub Action can fail builds if new endpoints introduce Basic Auth without corresponding logging controls.

Frequently Asked Questions

Why is structured logging important when using Basic Auth in FastAPI?
Structured logs with username, client IP, path, method, and correlation IDs enable detection of brute-force attempts, impossible travel, and forensic investigations. Without them, monitoring rules cannot reliably trigger alerts and security teams lack the context needed to investigate incidents.
Can middleware help with logging correlation in FastAPI Basic Auth flows?
Yes. A correlation ID middleware assigns a unique ID per request and attaches it to logs, making it easier to trace authentication events across services and to integrate with monitoring systems that alert on anomalous patterns.