Insufficient Logging in Fastapi with Basic Auth
Insufficient Logging in Fastapi with Basic Auth — how this specific combination creates or exposes the vulnerability
Insufficient Logging becomes more consequential when Basic Authentication is used in FastAPI because the protocol inherently exposes credentials in every request that is not protected by transport-layer protections and is not paired with robust server-side audit trails. Basic Auth sends an Authorization header containing a base64-encoded username:password pair on each request. If FastAPI does not log enough context—such as the endpoint accessed, the timestamp, the source IP, and whether the credentials were accepted or rejected—an attacker can probe accounts without leaving a traceable record. Without logs correlating authentication outcomes to request identifiers, incident responders cannot reconstruct the sequence of probes that led to a successful login, and automated security checks cannot reliably detect credential-stuffing patterns.
When combined with missing or inconsistent logging, additional risk categories identified by middleBrick can compound the issue. For example, BOLA/IDOR may be exercised if an authenticated but low-privilege account is logged without sufficient detail to track horizontal privilege escalation attempts across resources. Input Validation findings may also be harder to triage if request bodies and authentication decisions are not captured in structured logs. Even findings related to Rate Limiting can be difficult to enforce when logs omit the frequency of failed logins per credential or per IP. middleBrick’s Authentication and BOLA/IDOR checks specifically look for weak logging around authentication events, because unverified acceptance of credentials without a reliable audit trail is a direct indicator of insufficient observability.
Logging should include enough information to support forensic reconstruction while avoiding logging the raw password. A secure approach in FastAPI is to log the fact that an authentication attempt occurred, the username (not the password), the outcome (success/failure), the request path, the HTTP method, the client IP, and a request-scoped identifier. Structured JSON logging with consistent fields makes it easier to feed logs into SIEM or monitoring tools and enables automated detection of patterns such as repeated failures for a single user or bursts from a single IP. middleBrick’s scan can surface gaps when authentication logs lack these contextual fields, which hampers detection of abuse and complicates compliance mapping to frameworks such as OWASP API Top 10 and SOC2.
Basic Auth-Specific Remediation in Fastapi — concrete code fixes
To address insufficient logging while using HTTP Basic Authentication in FastAPI, implement structured logging for every authentication attempt and avoid logging secrets. Below is a complete, syntactically correct example that demonstrates dependency injection for the credentials, a reusable logging helper, and secure handling of the Authorization header.
import base64
import logging
import re
from fastapi import FastAPI, Depends, HTTPException, Header, Request, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
app = FastAPI()
security = HTTPBasic()
logger = logging.getLogger("auth_audit")
# Structured logging helper
audit_logger = logging.getLogger("api_auth_audit")
if not audit_logger.handlers:
handler = logging.StreamHandler()
audit_logger.addHandler(handler)
audit_logger.setLevel(logging.INFO)
def decode_credentials(credentials: HTTPBasicCredentials):
# Do not log credentials; decode username only for auditing
username = credentials.username
return username
def audit_log(
request: Request,
username: str,
outcome: str,
authorization_header: str = None,
):
# Log only non-sensitive information; never log raw password
# Remove or redact any bearer tokens or passwords if present
safe_header = authorization_header
if safe_header:
# Ensure we do not accidentally log a password in debug form
safe_header = re.sub(r':[^\\s]+', ':REDACTED', safe_header)
audit_logger.info(
f"{{\"timestamp\": \"{request.state.log_timestamp}\", "
f"\"method\": \"{request.method}\", "
f"\"path\": \"{request.url.path}\", "
f"\"username\": \"{username}\", "
f"\"outcome\": \"{outcome}\", "
f"\"client_host\": \"{request.client.host}\", "
f"\"authorization_header\": \"{safe_header}\"}}"
)
@app.middleware("http")
async def add_request_state_and_log(request: Request, call_next):
# Assign a log-friendly timestamp
from datetime import datetime
request.state.log_timestamp = datetime.utcnow().isoformat()
response = await call_next(request)
return response
@app.post("/protected")
async def protected_route(
credentials: HTTPBasicCredentials = Depends(security),
request: Request = None
):
username = decode_credentials(credentials)
# In real use, validate credentials against a secure store
if credentials.username != "admin" or credentials.password != "correct_hashed_password_placeholder":
audit_log(request, username, "failure", request.headers.get("authorization"))
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Basic"},
)
audit_log(request, username, "success", request.headers.get("authorization"))
return {"message": f"Hello {username}"}
This pattern ensures that each authentication event is recorded with a timestamp, method, path, username, outcome, and client host, while the password is redacted. For production, configure logging to output to a secure, centralized system and enforce HTTPS so that Basic Auth credentials are not exposed in transit. middleBrick’s Authentication and BOLA/IDOR checks can validate that such logging is present and that logs contain sufficient fields to support incident response.
Additionally, pair logging with operational controls: implement rate limiting to reduce brute-force risk, rotate credentials regularly, and avoid reusing the same credentials across environments. middleBrick’s Rate Limiting and Authentication scans will highlight missing or ineffective logging around auth boundaries, helping you maintain observability without exposing sensitive data in logs.