HIGH api key exposurefastapijwt tokens

Api Key Exposure in Fastapi with Jwt Tokens

Api Key Exposure in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

In FastAPI applications that use JWT tokens for authentication, developers sometimes inadvertently expose static API keys through insecure handling, logging, or configuration. When API keys are embedded in route logic, middleware, or debug output alongside JWT validation, they may be returned in responses or logged in plaintext. This occurs when authorization logic conflates API-level access control with token-based identity and exposes key material through verbose error messages or misconfigured CORS and exception handlers.

A typical misconfiguration is attaching an API key as a header or query parameter and passing it through to downstream services without scrubbing it. For example, a route that forwards an incoming Authorization header to a backend microservice may propagate the key if the JWT payload is used to construct outbound requests without removing sensitive headers. MiddleBrick tests such cross-layer exposures as part of Data Exposure and Unsafe Consumption checks, identifying when keys leak through responses or logs while JWT validation appears intact.

Another scenario involves OpenAPI spec generation where paths reference securitySchemes that mix an API key in a header with an HTTP bearer scheme using JWT tokens. If the spec defines multiple security requirements and runtime validation does not enforce strict separation, clients may receive key material in examples or schema descriptions. Additionally, during unauthenticated LLM endpoint probing, an attacker could attempt to coax key disclosure via crafted prompts if the endpoint reflects authorization details in error payloads.

Middleware that logs request and response headers indiscriminately may capture and persist API keys when exceptions occur during JWT decoding. If key identifiers appear in URLs or query strings, they may be stored in access logs and later exfiltrated. Since JWT tokens are often validated early, developers may assume downstream calls are safe, but failing to strip or mask sensitive identifiers before logging or forwarding creates an inadvertent channel for key exposure.

Dependency on environment variables is common, yet incorrect usage can lead to keys being serialized into error responses. For instance, catching validation errors from PyJWT and returning the raw exception detail may expose configuration keys if the error message includes variable interpolation. This is especially risky when combined with overly permissive CORS or when health endpoints return configuration metadata. MiddleBrick’s Data Exposure and Property Authorization checks flag these patterns by correlating spec definitions with runtime responses.

Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes

To remediate exposure when using JWT tokens in FastAPI, enforce strict separation between identity claims and API keys, and ensure keys never appear in responses or logs. Use dependency injection to validate JWTs and explicitly drop sensitive headers before forwarding requests. Below are concrete, working examples that illustrate secure patterns.

Secure JWT validation without leaking headers

from fastapi import FastAPI, Depends, Header, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from typing import Optional

app = FastAPI()
security_scheme = HTTPBearer()

def decode_jwt(token: str) -> dict:
    # Use your public key or secret and appropriate algorithms
    return jwt.decode(token, options={"verify_exp": True})

async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security_scheme)):
    try:
        payload = decode_jwt(credentials.credentials)
        return payload
    except jwt.PyJWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
            headers={"WWW-Authenticate": "Bearer"},
        )

@app.get("/items/")
async def read_items(user: dict = Depends(get_current_user), x_api_key: Optional[str] = Header(None)):
    # Explicitly do not forward or log x_api_key; if required, scrub it before any external call
    if x_api_key:
        # Validate or map key internally without reflecting it back
        pass
    return {"data": "safe"}

Removing sensitive headers before outbound calls

import httpx
from fastapi import Depends

def build_httpx_client():
    return httpx.AsyncClient()

async def call_backend_service(
    user: dict = Depends(get_current_user),
    api_key: Optional[str] = Header(None),
    client: httpx.AsyncClient = Depends(build_httpx_client)
):
    headers = {"Authorization": f"Bearer {user['sub']}"}
    # Never forward incoming API key; if backend requires a key, retrieve it securely from a vault
    # Do not include 'api_key' in headers if it originated from the client
    response = await client.get("https://internal.service/data", headers=headers, timeout=10.0)
    response.raise_for_status()
    return response.json()

Logging and error handling hygiene

Ensure that log statements exclude header values and that exception handlers do not serialize sensitive data:

import logging
from fastapi import Request

logger = logging.getLogger("api")

@app.middleware("http")
async def scrub_logging_middleware(request: Request, call_next):
    # Avoid logging headers that may contain keys
    safe_headers = {k: "***" if k.lower() == "authorization" else v for k, v in request.headers.items()}
    logger.info(f"Request: {request.method} {request.url} headers={safe_headers}")
    response = await call_next(request)
    return response

OpenAPI spec hygiene

When using FastAPI’s automatic docs, avoid mixing security schemes that imply key usage in JWT-secured endpoints. Define separate security schemes and apply them per-path to prevent examples from exposing keys.

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

app.security_schemes = {
    "bearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"},
    # Do not define an API key scheme for endpoints that use JWT only
}

def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema
    openapi_schema = get_openapi(
        title="Secure API",
        version="1.0.0",
        routes=app.routes,
    )
    # Ensure paths using JWT do not reference an API key security requirement
    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

Frequently Asked Questions

Can JWT tokens themselves be leaked in error responses when using FastAPI?
Yes, if exception handlers return raw validation errors that include token strings or internal configuration. Always sanitize error details and avoid echoing the Authorization header or decoded token content in responses.
How does MiddleBrick detect Api Key Exposure when JWT tokens are involved?
MiddleBrick runs parallel checks including Data Exposure and Unsafe Consumption. It correlates OpenAPI security scheme definitions with runtime responses to identify when API keys or sensitive headers are reflected, logged, or exposed while JWT validation is active.